<?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: fdjedkdls-spec</title>
    <description>The latest articles on DEV Community by fdjedkdls-spec (@fdjedkdlsspec).</description>
    <link>https://dev.to/fdjedkdlsspec</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4011501%2Fbd8eccf2-6225-4c21-9667-8f981f94390b.png</url>
      <title>DEV Community: fdjedkdls-spec</title>
      <link>https://dev.to/fdjedkdlsspec</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fdjedkdlsspec"/>
    <language>en</language>
    <item>
      <title>AI-Assisted AuthZ Review: Reading Permission Boundaries in Ory Kratos</title>
      <dc:creator>fdjedkdls-spec</dc:creator>
      <pubDate>Sat, 04 Jul 2026 00:12:17 +0000</pubDate>
      <link>https://dev.to/fdjedkdlsspec/ai-assisted-authz-review-reading-permission-boundaries-in-ory-kratos-31cg</link>
      <guid>https://dev.to/fdjedkdlsspec/ai-assisted-authz-review-reading-permission-boundaries-in-ory-kratos-31cg</guid>
      <description>&lt;p&gt;&lt;em&gt;Second in a series on using AI to review authorization — not to spray reports.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Companion reference: &lt;a href="https://gist.github.com/fdjedkdls-spec/7b6788d2d42e8a30a6be5108ed50480c" rel="noopener noreferrer"&gt;AuthZ Smell Catalog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Why AuthZ review is not vulnerability spraying
&lt;/h2&gt;

&lt;p&gt;The cheapest thing an AI can do in security is generate suspicion. Point a model at a&lt;br&gt;
codebase and it will hand you fifty "possible IDORs" before you finish your coffee. Almost&lt;br&gt;
all of them are wrong — guarded three lines up, scoped at the data layer, or protected at a&lt;br&gt;
boundary the model never saw.&lt;/p&gt;

&lt;p&gt;That flood is exactly why several bug bounty programs spent 2026 tightening or pausing:&lt;br&gt;
they were drowning in confident, plausible, wrong reports.&lt;/p&gt;

&lt;p&gt;So this review inverts the usual loop. The AI's job is not to find bugs — it is to&lt;br&gt;
&lt;strong&gt;over-generate hypotheses cheaply&lt;/strong&gt;. My job is to &lt;strong&gt;kill&lt;/strong&gt; them. What survives that killing&lt;br&gt;
is the only thing worth a human's time, and the record of what died is more useful than the&lt;br&gt;
record of what lived.&lt;/p&gt;

&lt;p&gt;The artifact of an honest review is therefore not a finding. It's a &lt;strong&gt;kill table&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Target and scope
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Target:&lt;/strong&gt; &lt;a href="https://github.com/ory/kratos" rel="noopener noreferrer"&gt;Ory Kratos&lt;/a&gt; — an open-source identity and
user-management server (login, registration, recovery, verification, sessions, self-service
settings). Source-available, Apache-2.0.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why Kratos:&lt;/strong&gt; it is exactly the shape where authorization goes wrong — multiple identities,
a public API &lt;em&gt;and&lt;/em&gt; an admin API, and (in Ory's hosted product) multi-tenancy. If a boundary
is fragile, this is where it shows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope of this write-up:&lt;/strong&gt; &lt;em&gt;source reading only&lt;/em&gt;, on the public repository, single-tenant
OSS build. No hosted target was touched. Nothing here is an undisclosed finding — the point
is the &lt;strong&gt;method and the boundary design&lt;/strong&gt;, and where relevant, how the design held against
the hypotheses I tested. This maps to the reproduction tiers we track: everything below is
&lt;code&gt;repo_only&lt;/code&gt;, and I say so explicitly rather than implying it reaches a live product.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What this review does and does not claim.&lt;/strong&gt; In this limited, repo-only review, the&lt;br&gt;
hypotheses I tested were killed. This is &lt;em&gt;not&lt;/em&gt; a claim that Kratos has no vulnerabilities,&lt;br&gt;
and it is not a security audit. It is a case study in how AI-assisted AuthZ review can&lt;br&gt;
avoid false positives — how to &lt;em&gt;kill&lt;/em&gt; a suspicion instead of shipping it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  3. What the AI suspected
&lt;/h2&gt;

&lt;p&gt;I let cheap finders over-generate against the &lt;a href="https://gist.github.com/fdjedkdls-spec/7b6788d2d42e8a30a6be5108ed50480c" rel="noopener noreferrer"&gt;AuthZ Smell Catalog&lt;/a&gt;. The raw candidate&lt;br&gt;
list, unfiltered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;H1 — Admin API has no authorization in code.&lt;/strong&gt; Identity CRUD, session deletion, and
courier endpoints on the admin API have no per-request permission check in the handler.
&lt;em&gt;(Catalog §01 object-id substitution, §13 middleware-only authorization.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H2 — Cross-identity / cross-tenant read.&lt;/strong&gt; Can one identity read another's data via
&lt;code&gt;/sessions/whoami&lt;/code&gt;, identity lookups, or an admin identity fetch? &lt;em&gt;(Catalog §04 tenant id
from client input, §05 cross-tenant leak via related object.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H3 — Recovery / verification token reuse.&lt;/strong&gt; Are one-time tokens actually one-time?
&lt;em&gt;(Catalog §09 invite/share token reuse.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H4 — Settings-flow identity confusion.&lt;/strong&gt; Can the self-service settings flow be pointed at
&lt;em&gt;another&lt;/em&gt; identity's traits? &lt;em&gt;(Catalog §02 ownership vs reachability, §07 stale privilege.)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H5 — Tenant assignment from payload.&lt;/strong&gt; Can an admin-create/update set an arbitrary network
id and cross the tenant boundary? &lt;em&gt;(Catalog §04.)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Five confident hypotheses. This is the part AI is good at. Now the part it can't do.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. How we tried to kill each hypothesis
&lt;/h2&gt;

&lt;p&gt;The rule: &lt;strong&gt;assume each is by-design until a concrete test says otherwise, and default to&lt;br&gt;
killing it.&lt;/strong&gt; For source-only review, the "test" is: can I trace a &lt;em&gt;user-reachable&lt;/em&gt; path where&lt;br&gt;
the invariant actually breaks — not just a handler that &lt;em&gt;looks&lt;/em&gt; unguarded?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;H1 — Admin API "missing" authorization → KILLED (by design).&lt;/strong&gt;&lt;br&gt;
Kratos deliberately ships the admin API with &lt;em&gt;no&lt;/em&gt; built-in authorization. Ory's own&lt;br&gt;
documentation states the admin API must be protected at the network boundary (ingress, a&lt;br&gt;
reverse proxy, Oathkeeper) and never exposed publicly. So "no authz check in the handler" is&lt;br&gt;
not a missing guard — it is the guard living one layer out, exactly the false-positive shape&lt;br&gt;
in Catalog &lt;strong&gt;§13 (middleware/deployment-layer authorization)&lt;/strong&gt;. A report of "admin API allows&lt;br&gt;
identity CRUD without auth" is by-design and would be closed as such. Killed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;H2 — Cross-identity / cross-tenant read → KILLED (chokepoint design).&lt;/strong&gt;&lt;br&gt;
This is the interesting one. Kratos does not scatter tenant checks across handlers. Its&lt;br&gt;
persistence layer runs every query through a &lt;strong&gt;network Contextualizer&lt;/strong&gt; that injects the&lt;br&gt;
network id (&lt;code&gt;nid&lt;/code&gt;) into the SQL — the data-access layer itself filters by tenant, centrally.&lt;br&gt;
A handler &lt;em&gt;cannot&lt;/em&gt; accidentally read across the boundary, because the boundary is enforced&lt;br&gt;
below the handler, at the one place every read funnels through. On the public API, identity&lt;br&gt;
access is derived from the &lt;em&gt;session's&lt;/em&gt; identity, never from a client-supplied id. To break&lt;br&gt;
H2 you would have to find a read path that bypasses the persister entirely — and I found no&lt;br&gt;
user-reachable one in this build. Killed. And worth noting as a pattern: concentrating the&lt;br&gt;
tenant filter at the data-access layer collapses the whole class into a single auditable&lt;br&gt;
point — which is why these particular hypotheses died here (Catalog §B).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;H3 — Token reuse → KILLED.&lt;/strong&gt;&lt;br&gt;
Recovery and verification tokens are single-use and time-boxed; redemption invalidates the&lt;br&gt;
token in the same transaction. Replay after use fails. Killed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;H4 — Settings-flow identity confusion → KILLED.&lt;/strong&gt;&lt;br&gt;
The settings flow binds to the identity resolved from the authenticated session. The identity&lt;br&gt;
being modified is not taken from client input, so you cannot retarget the flow at someone&lt;br&gt;
else's traits. Killed (Catalog §02 — read-reachability is not write-reachability, and here&lt;br&gt;
even read is session-bound).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;H5 — Tenant from payload → KILLED.&lt;/strong&gt;&lt;br&gt;
The network id is derived from context, not from the request body. An admin create/update&lt;br&gt;
cannot smuggle a foreign &lt;code&gt;nid&lt;/code&gt;. Killed.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. The kill table
&lt;/h2&gt;

&lt;p&gt;The deliverable of the whole review, on one screen:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Hypothesis&lt;/th&gt;
&lt;th&gt;Catalog&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;Why it died&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;H1&lt;/td&gt;
&lt;td&gt;Admin API missing authz&lt;/td&gt;
&lt;td&gt;§01, §13&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;by-design&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;authz is at the network boundary, not the handler — documented&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H2&lt;/td&gt;
&lt;td&gt;Cross-identity / cross-tenant read&lt;/td&gt;
&lt;td&gt;§04, §05&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;defended&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;nid&lt;/code&gt; enforced at the persister via the Contextualizer; public reads are session-bound&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H3&lt;/td&gt;
&lt;td&gt;Recovery/verification token reuse&lt;/td&gt;
&lt;td&gt;§09&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;defended&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;single-use, time-boxed, invalidated on redemption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H4&lt;/td&gt;
&lt;td&gt;Settings-flow identity confusion&lt;/td&gt;
&lt;td&gt;§02, §07&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;defended&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;flow bound to the session identity, not client input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H5&lt;/td&gt;
&lt;td&gt;Tenant assignment from payload&lt;/td&gt;
&lt;td&gt;§04&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;defended&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;nid&lt;/code&gt; from context, not request body&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Five hypotheses in. Zero findings out. &lt;strong&gt;This is a successful review, not a failed one&lt;/strong&gt; —&lt;br&gt;
and to be exact, it is a successful review &lt;em&gt;of five hypotheses&lt;/em&gt;, not a clean bill of health&lt;br&gt;
for Kratos.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. False-positive patterns worth naming
&lt;/h2&gt;

&lt;p&gt;Two shapes here generalize far beyond Kratos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deployment-layer authorization reads as "missing" authorization.&lt;/strong&gt; An endpoint with no
in-code check is a red flag &lt;em&gt;only&lt;/em&gt; if nothing outside the code guards it. Admin planes,
internal services, and "protect this at the ingress" designs all trip a naive AI. Always ask
&lt;em&gt;where else could the guard live&lt;/em&gt; before reporting (Catalog §13).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A chokepoint boundary looks unguarded per-handler.&lt;/strong&gt; When the real boundary is enforced at
a single data-access layer, every individual handler looks naked. The correct review question
flips from "does this handler check?" to "&lt;strong&gt;can anything reach the data without passing the
chokepoint?&lt;/strong&gt;" (Catalog §B, §12 alternate-path).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  7. What survived and what did not
&lt;/h2&gt;

&lt;p&gt;None of the hypotheses I tested survived source-only review — and the &lt;em&gt;reason&lt;/em&gt; is worth&lt;br&gt;
publishing: Kratos concentrates its tenant boundary in one place (the persister's&lt;br&gt;
Contextualizer) and derives identity from the session rather than from client input. That&lt;br&gt;
design choice is precisely what made four of my five hypotheses collapse to one question, and&lt;br&gt;
that question had a clean answer.&lt;/p&gt;

&lt;p&gt;If I were to keep going, the only honest next move would be to enumerate every ingress that&lt;br&gt;
could reach persisted data &lt;em&gt;without&lt;/em&gt; the persister — background jobs, imports, any raw query.&lt;br&gt;
In the OSS build there is no user-reachable one. That negative result is real signal, and it&lt;br&gt;
is tier &lt;code&gt;repo_only&lt;/code&gt;: I am not claiming it holds against any specific hosted deployment.&lt;/p&gt;
&lt;h2&gt;
  
  
  8. Lessons for AI-assisted security review
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Let AI over-generate; make humans the kill switch.&lt;/strong&gt; The value is in the rejection, not
the suspicion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default to by-design.&lt;/strong&gt; Assume the boundary is intentional until a concrete, reachable
path proves otherwise. This single bias would have prevented most of 2026's report-spam.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find the chokepoint first.&lt;/strong&gt; If a codebase enforces a boundary centrally, the review
collapses to "is the chokepoint ever bypassed?" — a far smaller, far more honest question.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name your reproduction tier out loud.&lt;/strong&gt; &lt;code&gt;repo_only&lt;/code&gt; is not &lt;code&gt;hosted_confirmed&lt;/code&gt;. Say which
one you have. Conflating them is how OSS reading turns into a false bounty claim.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish the kill table, not just the win.&lt;/strong&gt; The rejections &lt;em&gt;are&lt;/em&gt; the portfolio.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  9. How this feeds the AuthZ Smell Catalog
&lt;/h2&gt;

&lt;p&gt;Each kill sharpened a catalog entry's &lt;em&gt;confirm/kill&lt;/em&gt; column — the column that separates a real&lt;br&gt;
bug from a by-design behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;§13 gained the deployment-layer-authz false positive (from H1).&lt;/li&gt;
&lt;li&gt;§B / §04 gained the chokepoint-Contextualizer confirm test: &lt;em&gt;trace the response fields, and
ask whether any read path skips the central scoper&lt;/em&gt; (from H2).&lt;/li&gt;
&lt;li&gt;§09 gained the single-use-token replay test (from H3).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The catalog is not a static list; every real outcome — even a clean by-design result — feeds a&lt;br&gt;
sharper kill test back into it. That feedback loop is the asset, not the entry count.&lt;/p&gt;
&lt;h2&gt;
  
  
  10. Next step: from OSS case study to one real bounty target
&lt;/h2&gt;

&lt;p&gt;This review produces exactly one row for the outcome ledger — the honest kind, a defended&lt;br&gt;
target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;date&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2026-07-04, program=Ory Kratos (self-directed OSS review), source_type=oss_source_available,&lt;/span&gt;
&lt;span class="py"&gt;class&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;tenant_boundary, repro_tier=repo_only, human_verdict=by_design, final_status=not_applicable,&lt;/span&gt;
&lt;span class="py"&gt;payout_usd&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0, lesson="Contextualizer/nid chokepoint concentrates the tenant boundary; admin-API&lt;/span&gt;
&lt;span class="err"&gt;authz&lt;/span&gt; &lt;span class="err"&gt;is&lt;/span&gt; &lt;span class="err"&gt;deployment-layer&lt;/span&gt; &lt;span class="err"&gt;by&lt;/span&gt; &lt;span class="err"&gt;design&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="err"&gt;both&lt;/span&gt; &lt;span class="err"&gt;are&lt;/span&gt; &lt;span class="err"&gt;KILLs,&lt;/span&gt; &lt;span class="err"&gt;not&lt;/span&gt; &lt;span class="err"&gt;bugs.&lt;/span&gt; &lt;span class="err"&gt;Review&lt;/span&gt; &lt;span class="err"&gt;collapses&lt;/span&gt; &lt;span class="py"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;can anything&lt;/span&gt;
&lt;span class="err"&gt;reach&lt;/span&gt; &lt;span class="err"&gt;persisted&lt;/span&gt; &lt;span class="err"&gt;data&lt;/span&gt; &lt;span class="err"&gt;without&lt;/span&gt; &lt;span class="err"&gt;the&lt;/span&gt; &lt;span class="err"&gt;persister?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Row #1 in a ledger is not supposed to be a payout. It's supposed to be &lt;em&gt;true&lt;/em&gt;. From here, the&lt;br&gt;
next step is a single source-available target with a &lt;strong&gt;newly-added&lt;/strong&gt; permission boundary&lt;br&gt;
(a fresh RBAC, workspace, billing, or SSO/SCIM feature) — the un-picked-over surface — run&lt;br&gt;
through the same over-generate-then-kill loop, and logged as ledger row #2. One target. Not ten.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I use AI to reject candidates and humans to verify the few that survive. If that approach is&lt;br&gt;
useful to you, the &lt;a href="https://gist.github.com/fdjedkdls-spec/7b6788d2d42e8a30a6be5108ed50480c" rel="noopener noreferrer"&gt;AuthZ Smell Catalog&lt;/a&gt; is the companion reference this series builds on.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>backend</category>
      <category>cybersecurity</category>
      <category>security</category>
    </item>
    <item>
      <title>Using AI to find authorization bugs — and to prove the ones that aren't real</title>
      <dc:creator>fdjedkdls-spec</dc:creator>
      <pubDate>Thu, 02 Jul 2026 00:30:26 +0000</pubDate>
      <link>https://dev.to/fdjedkdlsspec/using-ai-to-find-authorization-bugs-and-to-prove-the-ones-that-arent-real-3m7d</link>
      <guid>https://dev.to/fdjedkdlsspec/using-ai-to-find-authorization-bugs-and-to-prove-the-ones-that-arent-real-3m7d</guid>
      <description>&lt;p&gt;Note: the production case study referenced at the end is withheld pending coordinated disclosure. No undisclosed vulnerabilities are described here.&lt;/p&gt;




&lt;p&gt;In 2026, bug bounty programs started closing their doors. Nextcloud suspended paid rewards, citing a flood of AI-generated, low-quality reports. Mattermost ended its program. The Internet Bug Bounty cut payouts by roughly 80%. The common thread isn't that AI can't find bugs — it's that most AI-assisted "findings" are &lt;em&gt;plausible but wrong&lt;/em&gt;, and triage teams are drowning in them.&lt;/p&gt;

&lt;p&gt;That reframes the problem. The scarce skill in 2026 isn't generating candidate vulnerabilities — a language model will hand you fifty before lunch. It's &lt;strong&gt;refuting the forty-nine that don't hold&lt;/strong&gt;. The differentiator is a method whose primary output is &lt;em&gt;correct negatives&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here's the method I use for source-available targets, and a worked example where the honest result was "there's no bug here."&lt;/p&gt;

&lt;h2&gt;
  
  
  The method: fan out to find, converge to refute
&lt;/h2&gt;

&lt;p&gt;Two stages, two different cost tiers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fan-out (cheap models).&lt;/strong&gt; Split the target's authorization surface into subsystems and read each in parallel. Each reader's only job is to surface &lt;em&gt;candidate&lt;/em&gt; broken invariants — places where an object is loaded by ID without an owner check, where a protected action might skip a re-auth gate, where two code paths authorize the same thing differently. Optimize for recall. Expect mostly false positives.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Adversarial verification (an expensive, high-reasoning model).&lt;/strong&gt; Take each candidate and try to &lt;em&gt;kill&lt;/em&gt; it. Default to REFUTED. A candidate survives only if you can cite the specific source lines proving the guard is absent &lt;em&gt;and&lt;/em&gt; the dangerous path is reachable &lt;em&gt;and&lt;/em&gt; nothing upstream already blocks it. Frame every survivor as a broken invariant — a one-sentence statement of the rule the system must never violate — and classify it as core versus config-dependent.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The output that matters most is the pile of refutations, each with a reason. That pile is what separates a report a triager trusts from a report that gets a program suspended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example: Ory Kratos settings &amp;amp; OIDC (verdict: defended)
&lt;/h2&gt;

&lt;p&gt;Ory Kratos is an open-source identity server. Its settings flow concentrates several privileged actions in one place — password change, email/recovery-address change, OIDC provider link/unlink — which is exactly the kind of surface where one inconsistent check becomes account takeover. A good place to look.&lt;/p&gt;

&lt;p&gt;The fan-out surfaced a genuinely tempting candidate. In the OIDC strategy, the continuity container that survives the identity-provider round-trip is &lt;strong&gt;not&lt;/strong&gt; identity-bound: at both pause and resume, the code omits the &lt;code&gt;WithIdentity&lt;/code&gt; option, so the owner check short-circuits on a nil identity. It is the &lt;em&gt;one&lt;/em&gt; pause/continue pair in the codebase that skips this binding. If you were pattern-matching for "missing check," you would write this up as a high-severity flow-hijack and hit submit.&lt;/p&gt;

&lt;p&gt;That would be slop. Here's why it's defended.&lt;/p&gt;

&lt;p&gt;The missing binding is only exploitable if the resume path derives its &lt;em&gt;write target&lt;/em&gt; from the unbound container. It doesn't. On the settings callback, the target identity comes from the live session cookie, the privilege gate is re-checked at the callback (not just at initiation), and the container's traits are never applied. On the login/registration callback, the target identity is derived from the cryptographically-signed OIDC subject in the validated token — again, not from the container. So the worst an attacker can do by replaying someone else's paused flow is link a provider to &lt;em&gt;their own&lt;/em&gt; account, or trip a collision check. The absent &lt;code&gt;WithIdentity&lt;/code&gt; is defense-in-depth that isn't load-bearing anywhere reachable.&lt;/p&gt;

&lt;p&gt;I checked the neighbors too. The privileged-session re-auth gate is enforced uniformly across every settings method. The "silent account merge" branch that would let an unverified email link onto an existing account is dead code in the open-source build — it's gated behind a policy hook that ships as nil. Each of these looked like a lead; each closed cleanly against the source.&lt;/p&gt;

&lt;p&gt;Verdict: the surface is well-built. Writing it up would have burned credibility for an "informational." The value delivered was the confidence to &lt;em&gt;not&lt;/em&gt; file — and a precise map of why the design holds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The class that does pay off
&lt;/h2&gt;

&lt;p&gt;The same method, pointed at a different target, surfaced a real one: &lt;strong&gt;an authorization guard that the main code path enforces but an alternate ingress fails to mirror.&lt;/strong&gt; A system revokes a user's access on the primary path, but a secondary, credential-authenticated entry point re-implements the authorization check and forgets one condition — so the "revoked" user still gets in through the side door. This class is dup-resistant (it requires understanding the specific system's trust model, not spraying requests), scanner-invisible (the semantics matter, not the syntax), and high-impact. Details after coordinated disclosure completes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is the durable skill in 2026
&lt;/h2&gt;

&lt;p&gt;The gatekeepers are raising walls specifically against volume. The researchers who thrive on the other side of those walls will be the ones whose AI-assisted work is &lt;em&gt;rigorous&lt;/em&gt;: findings framed as broken invariants, grounded in source, and — above all — filtered by a verification step that throws most of them away. Use AI to read more of the code than you ever could by hand. Then use it, adversarially, to prove yourself wrong before a triager has to.&lt;/p&gt;

&lt;p&gt;Signal, not volume. That's the whole game now.&lt;/p&gt;

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