<?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>DEV Community: Jacob R</title>
    <description>The latest articles on DEV Community by Jacob R (@jacob_r_627a001ff85b968a6).</description>
    <link>https://dev.to/jacob_r_627a001ff85b968a6</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%2F3965839%2Feb1ccc34-77a9-4ea7-8b83-f9198bbfe93a.png</url>
      <title>DEV Community: Jacob R</title>
      <link>https://dev.to/jacob_r_627a001ff85b968a6</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jacob_r_627a001ff85b968a6"/>
    <language>en</language>
    <item>
      <title>Your AI agent shouldn't hold your Stripe key. Here's the pattern that fixes it.</title>
      <dc:creator>Jacob R</dc:creator>
      <pubDate>Wed, 03 Jun 2026 06:16:07 +0000</pubDate>
      <link>https://dev.to/jacob_r_627a001ff85b968a6/your-ai-agent-shouldnt-hold-your-stripe-key-heres-the-pattern-that-fixes-it-1emo</link>
      <guid>https://dev.to/jacob_r_627a001ff85b968a6/your-ai-agent-shouldnt-hold-your-stripe-key-heres-the-pattern-that-fixes-it-1emo</guid>
      <description>&lt;p&gt;If you're wiring an autonomous agent up to real APIs — Stripe, Supabase, GitHub, your own backend — there's a design decision most stacks get wrong, and it's the same one that turns "the agent did something weird" into "the agent moved money."&lt;/p&gt;

&lt;h2&gt;
  
  
  The root problem: the credential &lt;em&gt;is&lt;/em&gt; the capability
&lt;/h2&gt;

&lt;p&gt;An API key is a bearer token. Whoever holds the bytes can do everything the key permits, for as long as the key lives, with no per-call limit and usually no per-call record. When you paste that key into an agent's environment, you've handed a non-deterministic process the &lt;strong&gt;full blast radius&lt;/strong&gt; of that key in one move. A prompt injection, a logging mistake, a retry loop — any of them now operates with your production credentials.&lt;/p&gt;

&lt;p&gt;Rotating after a leak means rotating &lt;em&gt;everywhere the key was ever embedded&lt;/em&gt;. And a leaked key is indistinguishable from a legitimate caller until you notice the bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: brokered egress
&lt;/h2&gt;

&lt;p&gt;The fix is to make the thing the agent holds &lt;strong&gt;not&lt;/strong&gt; the thing that grants access:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A human vaults the real provider secret once, in a broker the agent can't read.&lt;/li&gt;
&lt;li&gt;The agent gets a &lt;strong&gt;scoped, revocable token&lt;/strong&gt; it can present but never read.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;policy checkpoint sits on the outbound path&lt;/strong&gt;. The real secret is injected server-side only &lt;em&gt;after&lt;/em&gt; the request passes the rules — allowed host, allowed method, a spend ceiling, rate limits.&lt;/li&gt;
&lt;li&gt;Every allowed/blocked call lands in an append-only audit log.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent ── scoped token ──▶ Broker (policy + vaulted key) ──▶ Stripe / Supabase / ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three properties fall out of this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The secret can't be exfiltrated from the agent&lt;/strong&gt;, its prompt, or its logs — it was never there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revocation is one write&lt;/strong&gt;, not a key rotation across every system that ever touched the key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"The agent did something it shouldn't" becomes a synchronous 403&lt;/strong&gt; at the broker, not a forensic finding after the money moved.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The part people miss: injection still bites
&lt;/h2&gt;

&lt;p&gt;Even with the key behind a broker, a prompt-injected agent can still drive &lt;em&gt;policy-permitted&lt;/em&gt; actions. So the checkpoint has to do more than authenticate the caller — it has to &lt;strong&gt;taint requests that carry untrusted-content provenance&lt;/strong&gt; and refuse the sensitive ones. Authentication is not the same as good intent.&lt;/p&gt;

&lt;p&gt;And the audit log should be &lt;strong&gt;tamper-evident&lt;/strong&gt; (e.g. a hash chain), because the log is exactly what a capable attacker edits first.&lt;/p&gt;

&lt;h2&gt;
  
  
  When you &lt;em&gt;don't&lt;/em&gt; need this
&lt;/h2&gt;

&lt;p&gt;If your provider already issues short-lived, least-privilege OAuth tokens with native audit — use those. They're a stronger primitive than proxying a static key. The brokered model earns its keep when you're stuck handing out long-lived static secrets, which, for now, is still most of them.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I work on &lt;a href="https://www.vertex.blue" rel="noopener noreferrer"&gt;Vertex&lt;/a&gt;, which implements exactly this pattern — vault a key once, the agent gets a scoped token it can't read, with policy + spend caps + taint-based injection blocking on egress and a tamper-evident audit trail. Writing up the architecture because it generalizes regardless of whose broker you use.&lt;/em&gt;&lt;/p&gt;

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