June 20264 min readJohan Bretonneau

We Caught Ourselves Leaking a Secret, and the Gateway Said No
Why redaction in your app is necessary but never sufficient

Our own infrastructure agent tried to send a password to an LLM. Our own gateway's Security Shield blocked it before it left the network. Here's the incident, why the redaction step missed it, and why secret-scanning belongs at the LLM gateway.

We run an internal AI agent that diagnoses our own infrastructure. When a container misbehaves, it gathers the evidence (the service definition, the last lines of logs), hands it to an LLM, and proposes a root-cause analysis. Useful, boring, exactly the kind of glue work agents are good at.

Like any responsible team, we redact secrets before anything leaves our perimeter. The agent runs the bundle through a scrubbing step that strips passwords, API keys, tokens, and connection strings. Belt and braces.

Then one morning our alerts channel lit up:

🚨 security_shield: BLOCKED  threat=secrets  score=0.95

Our own LLM gateway had refused one of our own agent's requests. It had found a secret in a payload that our redaction step had already "cleaned."

That is simultaneously the worst news and the best news you can get.

The worst news: our redaction had a hole

The scrubbing step was what almost every team ships first: a hand-rolled denylist. A set of regexes that look for variable names like password, secret, token, api_key, plus a handful of known token shapes (sk-…, JWTs, connection-string passwords). It works, until it doesn't.

Here is a sanitized version of what slipped through, reproduced against the actual redaction code:

# what the agent collected (sanitized)
POSTGRES_PASSWORD: ********              ← caught (name matched "password")
GOOGLE_API_KEY:    ********              ← caught (name matched "api_key")
conn=postgres://app:********@db:5432     ← caught (connection-string rule)

DB_PASS:  pg_h0tfix_9921xQ              ← LEAKED ("pass" != "password")
pwd=hunter2hunter2                       ← LEAKED (list had "password|passwd", not "pwd")
Authorization: Bearer abk_live_9Hk29Lm…  ← LEAKED (only specific key shapes covered)

Three different secrets walked straight past the redaction:

  • a password under a variable named DB_PASS, because the denylist matched password, not pass;
  • a pwd= line, because the list had password and passwd, but nobody thought of pwd;
  • a Bearer token with a non-standard prefix, because the redactor only knew a few specific key formats.

None of these are exotic. They are the everyday vocabulary of real config files and real logs. A denylist is a list of the secrets you remembered. Production is full of the ones you didn't.

The best news: the gateway caught all of it anyway

Every request our agent makes goes through our LLM gateway, and the gateway runs a Security Shield on the way in. The Shield doesn't care which app, which SDK, which agent, or which model is involved. It scans the content of every request for secrets, PII, and prompt-injection before the request is ever brokered to a provider.

Its secret detector caught exactly what our redaction missed:

HIT  bearer\s+[A-Za-z0-9\-._~+/]{20,}      → "Bearer abk_live_9Hk29Lm…"
HIT  (password|passwd|pwd)\s*[:=]\s*\S{8,} → "pwd=hunter2hunter2"
→ threat=secrets, score=0.95 → request rejected (HTTP 400)

The password never reached the model. It never reached the provider. It never left our network. The Shield turned a silent data-leak-in-the-making into a loud, harmless 400 and a Slack ping.

The lesson: redaction is a control, the gateway is the backstop

It is tempting to read this as "our redaction was bad, let's fix the regex." We did fix the regex. But that misses the point.

You will never finish the denylist. Tomorrow it is a Slack webhook, an AWS AKIA… key, a GitHub ghp_… token, a vendor-specific Bearer format you have never seen. Every new service adds a new secret shape. A redaction step inside one app only knows the patterns that one team remembered, on the day they wrote it.

A gateway-level secret scanner is structurally different:

  • It sees every request. One enforcement point covers every app, every agent, every team, every model, including the experimental script someone wrote at 2 a.m. with no redaction at all.
  • It is centralized. Add one pattern once, and every caller is protected. No redeploying ten services.
  • It is the layer secrets actually pass through. Your app's redaction is opt-in and easy to forget. The gateway is the road; nothing reaches a provider without driving down it.
  • It is fast and tiered. A deterministic regex pass runs in under two milliseconds on every request; an optional LLM-based pass escalates only on suspicious ones, so you get coverage without paying latency on the 99% that are clean.

And here is the honest part, because honesty is the only thing that makes a security story worth reading: no single layer is perfect. In our incident, one secret slipped past both the redaction and the Shield's fast regex tier. That is not an argument against the Shield; it is the entire argument for layering. Redaction in the app, secret-scanning at the gateway, least-privilege on the secrets themselves, short-lived credentials. Each layer is a filter with holes; you stack them so the holes don't line up.

That is defense in depth. The redaction is a control. The gateway is the backstop. You want both, and you especially want the backstop to be the one thing every request is forced to cross.

We trust it enough to guard our own infrastructure

The reason we can tell this story with a straight face is that the agent that got blocked is ours, the gateway that blocked it is ours, and we found out from our own alerts, not from a customer, not from a breach report.

That is what the HiWay2LLM Security Shield does on every request that flows through the gateway: it scans for leaked secrets, personal data, and injection attempts before the call is ever made, with a deterministic fast path and an optional LLM deep-scan, and it ships the threat events straight to your SIEM. We point our own infrastructure agents at it for exactly the reason in this post, because the place to stop a secret is the one chokepoint every request has to cross.

If your agents and apps talk to LLMs through code paths you don't fully control (and at this point, whose don't?), put a backstop on the road they all have to take.

Start Saving →

No credit card required

Share

Was this useful?

Comments

Be the first to comment.