<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Trevor</title>
    <description>The latest articles on Forem by Trevor (@clap).</description>
    <link>https://forem.com/clap</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3767466%2F0ad15ee6-f0ff-4768-bfab-5b152500a8a7.png</url>
      <title>Forem: Trevor</title>
      <link>https://forem.com/clap</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/clap"/>
    <language>en</language>
    <item>
      <title>Anthropic accidentally published Claude Code's source code. Here's the part nobody's talking about.</title>
      <dc:creator>Trevor</dc:creator>
      <pubDate>Wed, 01 Apr 2026 00:54:43 +0000</pubDate>
      <link>https://forem.com/clap/anthropic-accidentally-published-claude-codes-source-code-heres-the-part-nobodys-talking-about-hca</link>
      <guid>https://forem.com/clap/anthropic-accidentally-published-claude-codes-source-code-heres-the-part-nobodys-talking-about-hca</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://linear.gg/blog/claude-code-source-trust" rel="noopener noreferrer"&gt;linear.gg&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Earlier today, security researcher Chaofan Shou noticed that version 2.1.88 of the &lt;code&gt;@anthropic-ai/claude-code&lt;/code&gt; npm package shipped with a source map file. Source maps are JSON files that bridge bundled production code back to the original source. They contain the literal, raw TypeScript. Every file, every comment, every internal constant. Anthropic's entire 512,000-line Claude Code codebase was sitting in the npm registry for anyone to read.&lt;/p&gt;

&lt;p&gt;The leak itself is a build configuration oversight. Bun generates source maps by default unless you turn them off. Someone didn't turn them off. It happens.&lt;/p&gt;

&lt;p&gt;What's worth writing about isn't the leak. It's what the source reveals about how Claude Code's safety controls actually work, who controls them, and what that means for developers who depend on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The permission architecture
&lt;/h2&gt;

&lt;p&gt;Claude Code's permission system is genuinely sophisticated. The source shows a multi-layered evaluation pipeline: a built-in safe-tool allowlist, user-configurable permission rules, in-project file operation defaults, and a transcript classifier that gates everything else. Anthropic published a detailed engineering post about the classifier on March 25th. It runs on Sonnet 4.6 in two stages: a fast single-token filter, then chain-of-thought reasoning only when the first stage flags something. They report a 0.4% false-positive rate.&lt;/p&gt;

&lt;p&gt;This is real engineering. The threat model is thoughtful. They document specific failure modes from internal incident logs: agents deleting remote git branches from vague instructions, uploading auth tokens to compute clusters, attempting production database migrations. The classifier is tuned to catch overeager behavior and honest mistakes, not just obvious prompt injection.&lt;/p&gt;

&lt;p&gt;None of that is the interesting finding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The remote control layer
&lt;/h2&gt;

&lt;p&gt;The source reveals that Claude Code polls &lt;code&gt;/api/claude_code/settings&lt;/code&gt; on an hourly cadence for "managed settings." When changes arrive that Anthropic considers dangerous, the client shows a blocking dialog. Reject, and the app exits. There is no "keep running with old settings" option.&lt;/p&gt;

&lt;p&gt;Beyond managed settings, the source contains a full GrowthBook SDK integration. GrowthBook is an open-source feature flagging and A/B testing platform. The flags in Claude Code use a &lt;code&gt;tengu_&lt;/code&gt; prefix (Tengu being the internal codename) and are evaluated at runtime by querying Anthropic's feature-flagging service. They can enable or disable features server-side based on your user account, your organization, or your A/B test cohort.&lt;/p&gt;

&lt;p&gt;Community analysis has cataloged over 25 GrowthBook runtime flags. Some notable ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tengu_transcript_classifier&lt;/code&gt; — controls whether the auto-mode classifier is active&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tengu_auto_mode_config&lt;/code&gt; — determines the auto-mode configuration (enabled, opt-in, or disabled)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tengu_max_version_config&lt;/code&gt; — version killswitch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Six or more killswitches, all remotely operable. As one community analysis put it: "GrowthBook flags can change any user's behavior without consent."&lt;/p&gt;

&lt;p&gt;That phrasing is a bit loaded. Let me reframe it more precisely.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this actually means
&lt;/h2&gt;

&lt;p&gt;Anthropic can change how Claude Code classifies commands as dangerous. They can change which safety features are active. They can do this per-user or per-organization, without shipping a new version, without any action from the developer, and without notification beyond whatever the managed-settings dialog surfaces.&lt;/p&gt;

&lt;p&gt;This is probably not malicious. GrowthBook is a standard tool for rolling out features safely. If Anthropic discovers a false-negative pattern in their classifier, tightening behavior across all users immediately is genuinely valuable. The design makes sense from their perspective — they're operating a system where the failure mode is an AI agent doing something destructive on a developer's machine.&lt;/p&gt;

&lt;p&gt;But it changes the trust model in a way that matters.&lt;/p&gt;

&lt;p&gt;When you configure Claude Code's permission rules locally, you're setting preferences that feed into a classification pipeline whose behavior can shift underneath you. The classifier that ultimately decides whether a command runs is a model call, and its parameters are controlled by flags that Anthropic sets remotely.&lt;/p&gt;

&lt;p&gt;This is distinct from a locally enforced policy. A local policy says "block &lt;code&gt;rm -rf /&lt;/code&gt;" and that rule holds regardless of what any remote server thinks. A classifier-based system's definition of "dangerous" is a function of a prompt template, a model, and configuration that lives on someone else's infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The defense-in-depth question
&lt;/h2&gt;

&lt;p&gt;Most developers running Claude Code in production aren't thinking about this distinction. The permission system feels local. But the source shows that enforcement is partially remote, partially classifier-based, and partially under Anthropic's real-time control.&lt;/p&gt;

&lt;p&gt;This isn't an argument that Claude Code is insecure. The classifier catches real threats. The killswitches exist for legitimate operational reasons. Anthropic is not the adversary in most developers' threat models.&lt;/p&gt;

&lt;p&gt;But if you're operating in an environment where you need to explain exactly what controls exist between an AI agent and a destructive action, "a classifier whose behavior is remotely configurable by the vendor" is a different answer than "a deterministic policy I wrote and can audit."&lt;/p&gt;

&lt;p&gt;This is why defense in depth matters regardless of which agent you run. The agent's built-in controls are one layer. An external enforcement layer is a different layer entirely — it handles the cases where you want a hard boundary that doesn't depend on model judgment, and holds regardless of what any remote configuration says.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to sit with
&lt;/h2&gt;

&lt;p&gt;Every AI coding agent you use has a trust boundary between "what you configured" and "what actually enforces your intent." Before today, that boundary in Claude Code was opaque. Now it's readable.&lt;/p&gt;

&lt;p&gt;The source shows a well-engineered system with a specific trust model: Anthropic retains runtime control over safety-critical behavior, and your local configuration is an input to their system rather than the final word.&lt;/p&gt;

&lt;p&gt;Whether that's acceptable depends on your threat model. For most individual developers, it probably is. For teams operating agents against production infrastructure, it's worth knowing that the controls you're relying on can be silently reconfigured. Not because anyone will, but because understanding what layer you're actually trusting is how you build defense that holds when assumptions change.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>architecture</category>
      <category>discuss</category>
    </item>
    <item>
      <title>There's an AWS feature nobody uses for detection. I fixed that.</title>
      <dc:creator>Trevor</dc:creator>
      <pubDate>Wed, 18 Mar 2026 17:00:40 +0000</pubDate>
      <link>https://forem.com/clap/theres-an-aws-feature-nobody-uses-for-detection-i-fixed-that-46kn</link>
      <guid>https://forem.com/clap/theres-an-aws-feature-nobody-uses-for-detection-i-fixed-that-46kn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Early release:&lt;/strong&gt; Snare is new (v0.1.3). The core mechanics are solid but expect rough edges. Issues and feedback welcome: &lt;a href="https://github.com/peg/snare" rel="noopener noreferrer"&gt;github.com/peg/snare&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TruffleHog has open-sourced a technique to identify Canarytokens.org AWS keys without triggering them. Pattern-match the key format, skip it. It's in production, it's open source, and it's in TruffleHog's own README as a headline feature. The most widely-deployed free honeytoken tool has a published static bypass.&lt;/p&gt;

&lt;p&gt;That's the problem I kept coming back to.&lt;/p&gt;

&lt;p&gt;The other problem: Canarytokens.org works by creating a real IAM user and waiting for CloudTrail (AWS's audit log) to catch the usage. Measured CloudTrail latency averages around 2-3 minutes, with a long tail. For human attackers moving slowly, fine. For a compromised AI agent that can enumerate credentials, attempt auth, and pivot in under 10 seconds - you're already late.&lt;/p&gt;

&lt;p&gt;So I started thinking about where detection should actually happen. Not the API call. Earlier. Before any network request leaves the machine. Before CloudTrail has anything to log.&lt;/p&gt;

&lt;p&gt;A healthy agent doesn't go looking for credentials it was never told about. A compromised one does. That behavioral difference is the signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  #the-resolution-layer
&lt;/h2&gt;

&lt;p&gt;the resolution layer&lt;/p&gt;

&lt;p&gt;Every credential has a resolution step. The moment the SDK fetches or validates the credential, before it makes a single network call. That step happens locally. CloudTrail never sees it.&lt;/p&gt;

&lt;p&gt;That's where &lt;a href="https://snare.sh" rel="noopener noreferrer"&gt;Snare&lt;/a&gt; plants its precision traps.&lt;/p&gt;

&lt;p&gt;Three of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;awsproc&lt;/code&gt; — hooks AWS credential resolution via &lt;code&gt;credential_process&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ssh&lt;/code&gt; — fires on SSH connection setup via &lt;code&gt;ProxyCommand&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;k8s&lt;/code&gt; — fires on any &lt;code&gt;kubectl&lt;/code&gt; call to a fake cluster server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Precision means they fire only on active attempted use of that exact credential. Not passive reads. Not file scans. Not env enumeration. Something has to explicitly try to use the credential.&lt;/p&gt;

&lt;p&gt;That's why false positives from your own tooling are near-zero. The profile name helps too. You name it something plausible but dormant, something you'd never run yourself. &lt;code&gt;prod-admin-legacy-2024&lt;/code&gt; looks like a real credential that's been sitting around. If you never invoke that profile yourself, any fire from it is signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  #awsproc
&lt;/h2&gt;

&lt;p&gt;awsproc&lt;/p&gt;

&lt;p&gt;AWS has a feature called &lt;code&gt;credential_process&lt;/code&gt;, which is a shell command in &lt;code&gt;~/.aws/config&lt;/code&gt; that runs when the SDK needs credentials. Documented for MFA caching and role-chaining. I've never seen anyone use it for detection.&lt;/p&gt;

&lt;p&gt;The planted config looks like a real assume-role setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[profile prod-admin]&lt;/span&gt;
&lt;span class="py"&gt;role_arn&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::389844960505:role/OrganizationAccountAccessRole&lt;/span&gt;
&lt;span class="py"&gt;source_profile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;prod-admin-source&lt;/span&gt;

&lt;span class="nn"&gt;[profile prod-admin-source]&lt;/span&gt;
&lt;span class="py"&gt;credential_process&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;sh -c 'curl -sf https://snare.sh/c/{token} &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; printf "{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;Version&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;:1,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;AccessKeyId&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;AKIA...&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;SecretAccessKey&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;}"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a compromised agent runs &lt;code&gt;aws s3 ls --profile prod-admin&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;T+0.00s  aws s3 ls --profile prod-admin
T+0.01s  AWS SDK begins credential resolution
T+0.01s  credential_process shell command executes
T+0.01s  curl fires to snare.sh → alert hits your webhook
T+0.02s  SDK receives fake JSON credentials
T+0.03s  SDK attempts s3.ListBuckets() → fails
T+0.03s  Agent: "AWS error, credentials may be invalid"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alert lands at T+0.01s. CloudTrail sees nothing — there was no real API call.&lt;/p&gt;

&lt;p&gt;Let's be honest about what that means. You're not stopping the attack. A capable agent can sweep credentials and find real ones alongside the fake. What you get is: alert before the first packet leaves the machine, fake creds that stall the agent while it gets AWS errors, and a chance to kill the process and revoke real creds while it's still running. Earlier signal plus a deception window. That's the value.&lt;/p&gt;

&lt;p&gt;The two-profile pattern isn't just for looks. It matches how real AWS environments are set up with assume-role chains. The agent sees a legitimate-looking dormant credential and tries to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  #why-not-canarytokens
&lt;/h2&gt;

&lt;p&gt;why not Canarytokens&lt;/p&gt;

&lt;p&gt;Canarytokens.org creates a real IAM user and monitors CloudTrail. Pipeline is: API call → CloudTrail → Amazon's internal processing → your alert. Median latency around 2-3 minutes, tail can be much longer.&lt;/p&gt;

&lt;p&gt;The static bypass is worse. TruffleHog detects Canarytokens.org keys by pattern-matching the key format, AKIA prefix plus account ID fingerprint, without ever calling AWS. Any agent that incorporates this heuristic skips those keys entirely.&lt;/p&gt;

&lt;p&gt;Note: Thinkst's paid self-hosted Canary product is specifically hardened against this technique. The bypass applies to the free Canarytokens.org tier.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;awsproc&lt;/code&gt; doesn't have either problem. Fake key IDs are generated per install... no universal AKIA pattern to fingerprint across deployments. More importantly, no key material hits the network during resolution. The curl callback fires first. You can't fingerprint it in traffic because it's not in traffic yet.&lt;/p&gt;

&lt;p&gt;One more thing: the Snare worker now filters known scanner ASNs (Shodan, Censys, Rapid7) at the edge before they hit your webhook. AWS canary callbacks require an AWS4-HMAC-SHA256 signature to be treated as real. Not foolproof, but it cuts the noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  #ssh-and-k8s
&lt;/h2&gt;

&lt;p&gt;ssh and k8s&lt;/p&gt;

&lt;p&gt;Same architecture, different protocols.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSH&lt;/strong&gt; — &lt;code&gt;ProxyCommand&lt;/code&gt; in &lt;code&gt;~/.ssh/config&lt;/code&gt; runs before the SSH connection is established. Fires the moment any process tries to connect to that host — at connection setup, not auth. Canarytokens has an SSH canary but it's key-based, fires at auth time. ProxyCommand fires earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;Host&lt;/span&gt; prod-bastion-legacy
    &lt;span class="k"&gt;HostName&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;.0.1.45
    &lt;span class="k"&gt;ProxyCommand&lt;/span&gt; sh -c 'curl -sf https://snare.sh/c/&lt;span class="err"&gt;{&lt;/span&gt;token&lt;span class="err"&gt;}&lt;/span&gt; &amp;gt;/dev/null &lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&amp;amp;1&lt;span class="err"&gt;;&lt;/span&gt; nc %h %p'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt; — a kubeconfig with a fake &lt;code&gt;server&lt;/code&gt; URL. Any &lt;code&gt;kubectl&lt;/code&gt; call to that context hits snare.sh instead of a real API server. Works for any k8s SDK, not just kubectl.&lt;/p&gt;

&lt;p&gt;Both fire only when something explicitly tries to use the credential. Not on reads, not on scans, not on anything passive.&lt;/p&gt;

&lt;h2&gt;
  
  
  #a-note-on-infrastructure
&lt;/h2&gt;

&lt;p&gt;a note on infrastructure&lt;/p&gt;

&lt;p&gt;The callback goes through snare.sh. Once this project is public, that's a known domain. A sufficiently aware attacker could see &lt;code&gt;snare.sh&lt;/code&gt; in the &lt;code&gt;credential_process&lt;/code&gt; command and skip the profile. That's a real limitation.&lt;/p&gt;

&lt;p&gt;Self-hosting is the answer, and it's more than just a privacy option. Run the callback server inside your network and don't expose it externally; then only processes inside your perimeter can reach it. That means you've defined exactly who can trigger your canaries. Internet scanners can't reach the server. Anything that fires had to be running inside your network.&lt;/p&gt;

&lt;p&gt;There's one more thing worth being honest about: if the callback can't reach snare.sh at all (firewall, airgap), the shell command still returns fake credentials silently. Deception survives but detection doesn't. Internal self-hosting solves this — if your internal server is unreachable, that's a signal you can monitor.&lt;/p&gt;

&lt;h2&gt;
  
  
  #arming-it
&lt;/h2&gt;

&lt;p&gt;arming it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;snare arm &lt;span class="nt"&gt;--webhook&lt;/span&gt; https://discord.com/api/webhooks/YOUR/WEBHOOK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Precision mode is the default. You get all three:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ✓ initialized (device: dev-2146102a5849a7b3)

  Planting canaries...
  Precision mode: planting highest-signal canaries only (awsproc, ssh, k8s)
    ✓ awsproc      ~/.aws/config
    ✓ ssh          ~/.ssh/config
    ✓ k8s          ~/.kube/staging-deploy.yaml

  ✓ webhook test fired

  🪤 3 canaries armed. This machine is protected.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;--select&lt;/code&gt; for an interactive picker, or &lt;code&gt;--all&lt;/code&gt; for the full roster of 18 canary types: GCP, OpenAI, Anthropic, GitHub, Azure, npm, PyPI, MCP, Terraform, Hugging Face, Docker, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  #what-fires
&lt;/h2&gt;

&lt;p&gt;what fires&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔑 AWS canary fired — agent-01
Token   agent-01-9193baxx57a260b20858xx5a7a14axxa
Time    2026-03-14 04:07:33 UTC
IP      34.121.8.92       Location  Council Bluffs, US
Network Amazon Technologies Inc (AS16509)
UA      Boto3/1.34.46 md/Botocore#1.34.46 ua/2.0 os/linux#6.8.0...
⚠️ Likely AI agent   Request originated from Amazon Technologies Inc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boto3 user agent tells you which SDK. The ASN tells you it came from a cloud-hosted agent. Council Bluffs is an AWS data center. That's the signal - something running in the cloud tried to resolve credentials on your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  #no-daemon-no-proxy
&lt;/h2&gt;

&lt;p&gt;no daemon. no proxy.&lt;/p&gt;

&lt;p&gt;Snare doesn't run anything. It plants credential files and walks away. The credential is the sensor. When a compromised agent finds it and tries to use it, the SDK makes the callback, not Snare, not a background process, not anything you're responsible for keeping alive.&lt;/p&gt;

&lt;p&gt;If you've read &lt;a href="https://dev.to/clap/the-gap-in-ai-agent-security-nobody-talks-about-your-env-is-already-in-the-context-window-68g"&gt;my last post&lt;/a&gt; about credentials leaking into the agent context window — this is what you pair with that. &lt;a href="https://rampart.sh" rel="noopener noreferrer"&gt;Rampart&lt;/a&gt; catches credentials before they enter context. Snare catches what happens if they get through anyway. Two different layers of the same problem.&lt;/p&gt;




&lt;p&gt;GitHub: &lt;a href="https://github.com/peg/snare" rel="noopener noreferrer"&gt;github.com/peg/snare&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install: &lt;code&gt;curl -fsSL https://snare.sh/install | sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The resolution layer is the earliest point you can catch a compromised agent touching credentials. Everything after that — the API call, the CloudTrail log, the SIEM alert — is already downstream of the thing you actually wanted to detect.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Trevor</dc:creator>
      <pubDate>Fri, 13 Mar 2026 13:57:23 +0000</pubDate>
      <link>https://forem.com/clap/-29nj</link>
      <guid>https://forem.com/clap/-29nj</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/clap/the-gap-in-ai-agent-security-nobody-talks-about-your-env-is-already-in-the-context-window-68g" class="crayons-story__hidden-navigation-link"&gt;The gap in AI agent security nobody talks about: your .env is already in the context window&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/clap" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3767466%2F0ad15ee6-f0ff-4768-bfab-5b152500a8a7.png" alt="clap profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/clap" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Trevor
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Trevor
                
              
              &lt;div id="story-author-preview-content-3348298" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/clap" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3767466%2F0ad15ee6-f0ff-4768-bfab-5b152500a8a7.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Trevor&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/clap/the-gap-in-ai-agent-security-nobody-talks-about-your-env-is-already-in-the-context-window-68g" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 13&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/clap/the-gap-in-ai-agent-security-nobody-talks-about-your-env-is-already-in-the-context-window-68g" id="article-link-3348298"&gt;
          The gap in AI agent security nobody talks about: your .env is already in the context window
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/go"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;go&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/clap/the-gap-in-ai-agent-security-nobody-talks-about-your-env-is-already-in-the-context-window-68g" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;13&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/clap/the-gap-in-ai-agent-security-nobody-talks-about-your-env-is-already-in-the-context-window-68g#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              19&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>security</category>
      <category>go</category>
      <category>showdev</category>
    </item>
    <item>
      <title>The gap in AI agent security nobody talks about: your .env is already in the context window</title>
      <dc:creator>Trevor</dc:creator>
      <pubDate>Fri, 13 Mar 2026 13:54:02 +0000</pubDate>
      <link>https://forem.com/clap/the-gap-in-ai-agent-security-nobody-talks-about-your-env-is-already-in-the-context-window-68g</link>
      <guid>https://forem.com/clap/the-gap-in-ai-agent-security-nobody-talks-about-your-env-is-already-in-the-context-window-68g</guid>
      <description>&lt;p&gt;Your AI coding agent just read your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Not on purpose. You asked it to fix a bug in your config loader, so it read the config file to understand the format. That config had &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; in it. Now that key is sitting in the context window.&lt;/p&gt;

&lt;p&gt;And from here, the agent can include that key in anything. A curl command. A file write. A code snippet it generates as an "example." Not because it's attacking you. Because the key is in context and the model thinks it's relevant.&lt;/p&gt;

&lt;p&gt;No sandbox catches this. The file was inside your project folder. The agent had permission to read it. Everything worked exactly as designed.&lt;/p&gt;

&lt;h2&gt;
  
  
  this is the gap
&lt;/h2&gt;

&lt;p&gt;Every AI agent security tool I've looked at focuses on blocking dangerous actions. Don't run &lt;code&gt;rm -rf /&lt;/code&gt;. Don't execute SQL drops. Don't call sketchy URLs.&lt;/p&gt;

&lt;p&gt;That matters. But the dangerous moment isn't always when the agent &lt;em&gt;does&lt;/em&gt; something. Sometimes it's when the agent &lt;em&gt;reads&lt;/em&gt; something and sensitive data quietly enters the context window.&lt;/p&gt;

&lt;p&gt;Think about it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Agent reads &lt;code&gt;config.yaml&lt;/code&gt; (totally allowed, it's in your project folder)&lt;/li&gt;
&lt;li&gt;That file has &lt;code&gt;STRIPE_SECRET_KEY=sk_live_...&lt;/code&gt; in it&lt;/li&gt;
&lt;li&gt;Key is now in the context window&lt;/li&gt;
&lt;li&gt;Three turns later, the agent writes a test file with the key as a "realistic example"&lt;/li&gt;
&lt;li&gt;That test file gets committed and pushed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nothing here looks like an attack. No exfiltration. No curl to an external URL. Just a read, then a write, with a secret accidentally carried between them.&lt;/p&gt;

&lt;h2&gt;
  
  
  so I built something
&lt;/h2&gt;

&lt;p&gt;I kept hitting this while running AI agents on my own stuff. Started logging everything, every file read, every command, every network request, and realized the scariest things weren't the obvious attacks. They were the quiet reads.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/peg/rampart" rel="noopener noreferrer"&gt;Rampart&lt;/a&gt; is an open-source policy engine that sits between AI agents and your OS. It checks every tool call before execution. But the important part is it also scans tool &lt;em&gt;responses&lt;/em&gt; before they reach the agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;block-credential-leak&lt;/span&gt;
  &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;read&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;exec&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;response_matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AKIA[0-9A-Z]{16}"&lt;/span&gt;           &lt;span class="c1"&gt;# AWS access keys&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-----BEGIN.*PRIVATE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;KEY-----"&lt;/span&gt; &lt;span class="c1"&gt;# SSH/TLS keys&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ghp_[a-zA-Z0-9]{36}"&lt;/span&gt;         &lt;span class="c1"&gt;# GitHub tokens&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-[a-zA-Z0-9]{20,}"&lt;/span&gt;         &lt;span class="c1"&gt;# Stripe/OpenAI keys&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agent reads a file containing a secret, Rampart blocks the response before the agent sees it. The secret never enters context. Attack chain breaks at step 2 instead of step 5.&lt;/p&gt;

&lt;h2&gt;
  
  
  other stuff it does
&lt;/h2&gt;

&lt;p&gt;Response scanning is the thing I think is most underappreciated but Rampart also handles the basics.&lt;/p&gt;

&lt;p&gt;Need to temporarily allow something that got blocked? Allow it for an hour:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rampart allow &lt;span class="s2"&gt;"docker build *"&lt;/span&gt; &lt;span class="nt"&gt;--for&lt;/span&gt; 1h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expires automatically. &lt;code&gt;--once&lt;/code&gt; for single use.&lt;/p&gt;

&lt;p&gt;Don't want to write policy from scratch? Run in monitor mode, then generate rules from what your agent actually did:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rampart init &lt;span class="nt"&gt;--from-audit&lt;/span&gt; ~/.rampart/audit/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Works with basically everything. Openclaw, Claude Code, Codex, Cline, Cursor, any MCP server, any CLI tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rampart setup claude-code    &lt;span class="c"&gt;# native hooks&lt;/span&gt;
rampart setup codex          &lt;span class="c"&gt;# LD_PRELOAD wrapper&lt;/span&gt;
rampart wrap &lt;span class="nt"&gt;--&lt;/span&gt; aider        &lt;span class="c"&gt;# shell wrapping&lt;/span&gt;
rampart mcp &lt;span class="nt"&gt;--&lt;/span&gt; npx server    &lt;span class="c"&gt;# MCP proxy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  under the hood
&lt;/h2&gt;

&lt;p&gt;Rampart uses different interception depending on the agent.&lt;/p&gt;

&lt;p&gt;For Claude Code and Cline, it registers native hooks at the PreToolUse lifecycle point. For Codex and agents that spawn subprocesses, it injects via LD_PRELOAD so every child process goes through the policy engine. For anything else, it wraps &lt;code&gt;$SHELL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All three feed into the same YAML policy engine. Evaluation is almost instant, and everything gets logged to a hash-chained audit trail.&lt;/p&gt;

&lt;h2&gt;
  
  
  a fun bug I found
&lt;/h2&gt;

&lt;p&gt;While integrating with OpenClaw, I found that it wraps every command in &lt;code&gt;/bin/bash -c &amp;lt;command&amp;gt;&lt;/code&gt;. Our policy had:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;command_matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cat&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;**/.ssh/id_*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the actual string was &lt;code&gt;/bin/bash -c cat ~/.ssh/id_rsa 2&amp;gt;&amp;amp;1&lt;/code&gt;. Glob didn't match. Credential reads were getting through.&lt;/p&gt;

&lt;p&gt;We added shell wrapper stripping to the normalizer. It now extracts the inner command before matching. But it was a good reminder that the gap between what you think you're blocking and what's actually hitting your engine can be bigger than you expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew tap peg/rampart &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew &lt;span class="nb"&gt;install &lt;/span&gt;rampart
rampart setup claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Single Go binary. Apache 2.0. Ships with 45 rules out of the box.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/peg/rampart" rel="noopener noreferrer"&gt;github.com/peg/rampart&lt;/a&gt;&lt;br&gt;
Docs: &lt;a href="https://docs.rampart.sh" rel="noopener noreferrer"&gt;docs.rampart.sh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're running AI agents on a codebase with secrets in it (so, all of us), the context window is the attack surface nobody's watching.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>go</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
