Skip to content
Code Recycle

Component · for humans & their agents

Oauth Consent Risk

verified · first-partyactively maintained$0 during beta (was $69)

The backdoor that survives the password reset. Scores OAuth consent grants by blast radius and persistence, and tells you which ones are still working after the remediation you just finished.

by Code Recycle

Get it free — beta

Every claim on this page is refundable if it is untrue — refund policy.

23 tests · 4/4 deliberate defects caught. Zero runtime dependencies.

The gap

A mailbox gets taken over. The response is well-rehearsed: reset the password, revoke sessions, re-enrol MFA, check the inbox rules. Everyone signs off.

None of that revokes a refresh token. If the attacker got a consent — from the user by phishing, or on the user's behalf after taking the account — that app holds a credential of its own. The password reset does not touch it. Re-enrolling MFA does not touch it. The app keeps reading mail through the front door, using a grant your organisation issued, until somebody revokes that service principal specifically.

  survivesRemediation(grants);
  // [{ appId: "…", level: "critical", survivesCredentialReset: true,
  //    reasons: ["holds a refresh token (offline_access) — a password reset, session revocation
  //               and MFA re-enrolment do NOT revoke it. The grant must be revoked specifically"] }]

That's the list to work through before calling an incident closed.

Application vs delegated: same string, different world

A delegated Mail.Read reads the mail of the one user who consented, while they are signed in. An application Mail.Read reads every mailbox in the tenant, with no user involved, forever.

Same scope name. Same consent dialog for an admin in a hurry. The audit log entry is identical. That is precisely how it gets waved through, so the permission type is worth more than any single scope in the score.

What drives the score

| factor | why it moves the number | |---|---| | self-escalation scopes | outranks data access — an app that can assign itself roles can award itself the rest later, quietly | | read organisational content | mail, files, sites, chat, contacts | | send-as | enough to commit the fraud, not just watch it | | application permission | every mailbox, no user present | | admin consent | applies to everyone at once | | offline_access | outlives your remediation | | unverified publisher | +10, and never a finding on its own | | localhost redirect URI | +5, and never on its own |

The last two matter as much as the first. Plenty of legitimate internal apps are unverified, and scoring that alone as a finding trains everyone to dismiss the signal — so it is worth nothing on the day it means something. Tests hold both to zero in isolation.

A high score is a question, not an accusation. Legitimate apps request alarming scopes for good reasons; a backup tool genuinely needs application-level mail access. This exists so a human reviews the twelve grants that could exfiltrate the organisation instead of the four hundred that could not.

Allowlisting is by app id, never by name

  reviewConsents(grants, { allowedAppIds: ["…"] });

Display names are attacker-controlled and not unique — registering an app called "Microsoft Teams" is free. A name-keyed allowlist would suppress exactly the grant you most needed to see.

This one is worth calling out: the first version of that test passed against a broken implementation, because the allowlist in the test never contained the display name it claimed to be testing. Mutating the code to consult names did not fail anything. The test now puts the attacker's chosen display name in the allowlist and asserts the grant is still reported.

Scope and limits

Scope names are Microsoft Graph's, normalised so Mail.Read and https://graph.microsoft.com/Mail.Read score identically. The families are ordinary constants — map another provider's scopes onto them and the scoring works unchanged.

| not included | why | |---|---| | Fetching grants from Graph | you fetch; this scores | | Revoking anything | scoring tool. Auto-revoking consents breaks legitimate integrations at 3am | | Detecting when consent was phished | needs sign-in correlation — see signin-spray-shape | | Rules the attacker left behind | inbox-rule-tripwire | | Suppressing repeat alerts | findings-delta |

Weights are a triage ordering, not a probability, and they are arguable — that is why every finding carries reasons and drivingScopes, so a reviewer can check the reasoning rather than trust the number.

01Capabilities

Does

  • + Role-based access control
  • + Security monitoring
  • + Token verification

Doesn’t

  • No exclusions declared

02Requirements & stack

Depends on

No declared dependencies

Credentials needed

None declared

Stack

03Community

No endorsements yet

No verified confirmations yet — be the first.

Confirmations come from verified purchasers, installers, vetted reviewers, or an installation outcome your org reported through the agent tools. They grade quality — security is verified separately, and community votes can never override the security gate.

Open an issue

Sign in to confirm — weight comes from verified usage, not vote count.

Nobody has reported anything yet — a success counts as a report too.

04Trust Passport

Full passport →
–/100

0/0 automated components pass. An automated score is never a security guarantee.

✓ Verified · first-partyreviewed Sep 20, 2026 · re-verification due Dec 19, 2026
  • publisher identity Publisher status verified; 1 verification(s) on file
  • malicious pattern scan No known malicious-behavior patterns across 7 source file(s) plus listing text
  • capability contract All 1 observed capability reference(s) match the declared manifest (1 declared as cited source(s), not contacted)
  • agent safety scan No injection patterns in agent-readable content
  • provenance No release signature or provenance attestation
  • behavioral sandbox Not performed in this environment — requires the production isolated runner (docs/sandbox-requirements.md). No untrusted code is ever executed on the application host.

Every listing must pass this review before it can be sold, and it is re-run on every release. Verification describes what we checked — it is not a guarantee that the software is safe.

VersionChannelReleasedNotes
0.1.0stableAug 12, 2026Initial extraction.