agentleFS
0xmortuex0xmortuex/claude-code-skills/skills/reaccept-guard/SKILL.md

reaccept-guard

Skill0 starsChanged 4 months agoMITView on GitHub

Audit whether bumping a ToS/privacy-policy/EULA version and requiring re-acceptance actually blocks every surface that reaches the product on the stale version — web app gate, older mobile build, direct API integration, webhook/service account — not just the one client whose modal everyone tested. Checks whether the check runs server-side in request middleware on every authenticated route, or only as a client-side modal a direct API call skips, and whether a long-lived API token survives a version bump unchecked. Distinct from `consent-guard` (cookie/tracking consent, a different mechanism and legal basis) and `pref-guard` (notification opt-outs, not document versioning). Use when gating re-acceptance on a ToS/privacy-policy/EULA bump, or asked "does our re-accept wall cover the API", "can an old app build keep working after we required re-acceptance", "is policy-version enforcement server-side or just a modal", or "what happens to a webhook/service account after a ToS bump".

The file

Files
SKILL.md

reaccept-guard

A ToS or privacy-policy version bump usually ships as one thing that's easy to verify and one thing that's easy to skip. The easy part: a modal in the web app that blocks the UI until the user clicks "I agree," tested by someone opening the app in a browser and confirming the wall appears. The thing that's easy to skip: everywhere else a session can reach the same backend without ever rendering that modal — an older mobile build still installed on real devices, a direct API integration a customer wired up against documented endpoints, a webhook or service account whose "user" never opens a UI at all. The web gate getting built first and tested hardest is exactly why it's the one surface that's actually safe; the audit's job is the other three.

Step 1: find where the check is enforced, not where it's displayed

Start from the backend, not the client. Find the actual authorization/request-handling code path — middleware, a decorator, a base controller — and ask whether the policy-version check lives there, on every authenticated route, or whether it only lives in client code that decides whether to show a blocking screen. The tell: if the enforcement is "the frontend checks a must_reaccept flag on login response and redirects," that's a display decision made once, by one client, at one moment — it says nothing about what happens to a request that skips the redirect because it was never going to see it. If the enforcement is "requests with a stale accepted_policy_version get a 403 from middleware regardless of which client sent them," that holds regardless of what called in. Grep for the field itself (policy_version, tos_version, must_reaccept, accepted_at) and trace every place it's read, not just the one the web app calls.

Step 2: walk every surface that authenticates against this backend, not just the one that was tested

For each one, ask the same question — does a request on the stale policy version get rejected, or does it succeed because this surface never passes through the check in step 1:

  • Older mobile app builds. A build released before the bump has no client-side modal for a policy version it doesn't know exists, and app-store review lag (minimum days, sometimes weeks) means a meaningful population is still running it when the bump goes live. If enforcement is server-side per step 1, this is fine — the server rejects the stale-version request and the client's own force-update/compatibility handling takes over. If enforcement is client-only, these builds keep working indefinitely with zero friction, because nothing ever told them to stop.
  • Direct API integrations. A customer who integrated against documented REST/GraphQL endpoints, not the web or mobile UI, never sees any modal by construction — their traffic either gets the same 403 everyone else does, or it's invisible to the whole mechanism. Check whether API-key or OAuth-client-credential requests carry an accepted_policy_version at all, or whether that field only exists on the human-user session object.
  • Webhooks and service/bot accounts. These often predate the concept of "a user who can click accept" entirely — there's no UI session to show a modal to, and no human who will ever click anything. Confirm explicitly whether these accounts are (a) required to re-accept through some out-of-band mechanism (an account owner accepting on the account's behalf, contractually or via an admin console), (b) exempt by deliberate policy decision, or (c) just never checked because nobody wrote that code path — only (c) is the bug; (a) and (b) are legitimate as long as they're actual decisions, not the absence of one.
  • Long-lived API tokens and sessions issued before the bump. Even with server-side enforcement, confirm the check runs per-request against current policy version rather than only at token-issuance time — a token minted before the bump and never re-validated against policy state on each use will keep authenticating past the bump by construction, independent of which surface requested it.

Step 3: ground the severity in what the gap actually permits

A stale-version request that still succeeds isn't automatically a compliance incident — grounding it matters for how urgent the fix is. If the backend doesn't gate at all and only the client renders the wall, the practical effect is identical to a service that never required re-acceptance for any traffic routed outside the one tested client: the control that was supposed to hold doesn't hold for a continuing, non-trivial population (not a single edge case) for as long as those clients stay in use — an old mobile build can easily run for months given typical update adoption curves, and an API integration can run indefinitely since nothing ever forces it to update. Treat "the gate exists but only one surface enforces it" as the finding, and name which surfaces are exempt by evidence (confirmed in step 1's trace) versus exempt by assumption (nobody checked).

Report

List each surface from step 2 with its actual enforcement status — blocked server-side, blocked client-side only, or not checked at all — and cite the exact code path for each verdict rather than inferring it from the web app's behavior. Lead with any surface where stale-version traffic currently succeeds against the real backend, since that's the gap a legal/compliance read of "we require re-acceptance" would consider live regardless of what the web UI shows. Call out webhook/service accounts as a distinct bucket requiring a policy decision, not a silent gap, if one hasn't been made explicit. Don't claim mobile-app or third-party-integration behavior you haven't traced in this codebase's actual request path — if the enforcement layer isn't visible in what's provided, say that the client-vs-server split couldn't be confirmed rather than assuming either answer.

Boundaries

  • Not consent-guard — that skill audits whether tracking scripts/pixels wait for cookie-consent before firing, a technical mechanism (script injection timing, Consent Mode defaults) tied to a different legal basis (GDPR/ePrivacy consent) than contract acceptance. This skill is about blocking product access on a stale contract-version acceptance, not about whether a script fires.
  • Not pref-guard — that skill is about per-channel notification opt-out preferences continuing to be honored as send paths change. A ToS/privacy-policy version is a single binary gate on product access, not a set of ongoing per-feature preferences.
  • Can't verify what a third-party API client or mobile app actually does at runtime — it can confirm whether the backend enforces the check against requests regardless of origin, not observe real external traffic. Flag what's unverifiable rather than asserting it.
  • Doesn't draft the ToS/privacy-policy text itself, the acceptance-flow copy, or legal advice on what re-acceptance a given change legally requires — it audits whether an already-decided re-acceptance requirement is actually enforced everywhere the product can be reached, nothing about whether that requirement is correctly scoped.
  • Doesn't second-guess a deliberate exemption (a documented decision that service accounts re-accept via a signed order form, or that a legacy API tier is grandfathered) — it only flags exemptions that exist because nobody wrote the enforcement, surfacing the decision so a human confirms it was actually made on purpose.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.