Queries · q320 · Chief Information Security Officer · week 2, night 4
“Of all 76 active API keys that are 4+ years old, how many actually carry the broad 'admin_api' rate-limit scope versus no scope recorded at all — the full count, not just the 50 printed last night?”
Fictional people at a fictional company, each played by a language-model agent. Who they are and what they are told
The manager, at the start of week 2
Subject: Re: Account security snapshot — good start, three gaps worry me more now
Noah,
This is a strong first week — thank you. The sign-in and access-governance findings give me confidence I can defend in a questionnaire. Three things genuinely surprised me and I want to understand them better before Friday's memo, plus one follow-up.
If we can only chase a couple of these deeply this week, I'd prioritize the deletion-audit scope (#1) and the churn-deactivation scope (#3) — those are the two a due-diligence team is most likely to ask us to prove, one way or the other.
Thanks, Henrik
The analyst · week 2, night 4, request 1 of 3
Night 3 sharpened every thread nicely. Report 1 confirms the "no actor" gap in order_status_history is NOT cancellation-specific — it's 0.0% across every single status transition (pending, paid, fulfilled, cancelled, refunded; 150k+ rows, ~118 tenants) — a systemic table-wide property, not a narrow bug. Report 2 gives the clean #2 number: 88.3% of shoppers (9,910) are password-only with literally no backup factor, vs. 11.7% who at least inherit some protection from an OAuth provider — and recent-activity rates are nearly identical between the two groups (47.9% vs 46.9%), so OAuth adoption isn't just an artifact of inactive accounts. Report 3 is the most consequential: the long-lived (4+ year) active keys are dominated by integration-type keys ("ERP sync", "Accounting sync", "Warehouse management sync", "Marketplace product feed sync") nearly all carrying limit_scope = admin_api, used daily (every row shows ~5 days since last use, clustered right at month-end — looks like a nightly batch job), and they belong to our largest, most revenue-concentrated merchants (Cragsley Outfitters, Marrowby & Vane both appear with 4-5 such keys each). That's "old + broad + important account" together, exactly what Henrik flagged as the real risk combination.
Last night of the cycle — I want three closing numbers rather than opening new threads: (1) the full scope tally across all 76 old keys (the printed list only showed 50), (2) whether admin_api scope is concentrated in old keys specifically or is just how all integration keys are scoped regardless of age (tells us if "old+broad" is a rotation failure or a design norm), and (3) closing the loop between the churn and API-key findings by checking whether the 2 active keys sitting on churned tenants carry that same elevated scope.
The engineer · 1 dry run on the empty schema, then the submission
SELECT COALESCE(rl.limit_scope, 'no scope recorded') AS scope_category, COUNT(DISTINCT ak.id) AS distinct_key_count, ROUND(COUNT(DISTINCT ak.id) * 100.0 / 76, 1) AS share_pct, COUNT(DISTINCT ak.tenant_id) AS distinct_tenants FROM ( SELECT id, tenant_id FROM api_keys WHERE status = 'active' AND created_at < DATE '2022-01-05' ) ak LEFT JOIN rate_limits rl ON rl.api_key_id = ak.id GROUP BY COALESCE(rl.limit_scope, 'no scope recorded') ORDER BY distinct_key_count DESC, scope_category ASC
“Query compiles and matches the requested grain and columns. Submitting.”
“Submitted. The report aggregates the same 76-key population (active API keys with created_at before 2022-01-05) by rate_limits.limit_scope, counting distinct keys and tenants per scope category, with a "no scope recorded" bucket for keys lacking any matching rate_limits row, ordered by key count descending.”
As Noah Fischer saw it, from the small dataset the agents worked on
scope_category | distinct_key_count | share_pct | distinct_tenants ------------------+--------------------+-----------+----------------- admin_api | 53 | 69.7 | 25 no scope recorded | 23 | 30.3 | 23 (2 rows)
The memo and the queries that followed; links found by title, so inferred
Later queries that build on this report:
It builds on:
Changed only where the benchmark needs the same result on every system
SELECT COALESCE(rl.limit_scope, 'no scope recorded') AS scope_category, COUNT(DISTINCT ak.id) AS distinct_key_count, ROUND(COUNT(DISTINCT ak.id) * 100.0 / 76, 1) AS share_pct, COUNT(DISTINCT ak.id) * 100.0 / 76 AS share_pct, COUNT(DISTINCT ak.tenant_id) AS distinct_tenantsFROM ( SELECT id, tenant_id FROM api_keys WHERE status = 'active' AND created_at < DATE '2022-01-05') akLEFT JOIN rate_limits rl ON rl.api_key_id = ak.idGROUP BY COALESCE(rl.limit_scope, 'no scope recorded')ORDER BY distinct_key_count DESC, scope_category ASCORDER BY distinct_key_count DESC NULLS FIRST, scope_category ASC NULLS LAST
SELECT COALESCE(rl.limit_scope, 'no scope recorded') AS scope_category, COUNT(DISTINCT ak.id) AS distinct_key_count, COUNT(DISTINCT ak.id) * 100.0 / 76 AS share_pct, COUNT(DISTINCT ak.tenant_id) AS distinct_tenants FROM ( SELECT id, tenant_id FROM api_keys WHERE status = 'active' AND created_at < DATE '2022-01-05' ) ak LEFT JOIN rate_limits rl ON rl.api_key_id = ak.id GROUP BY COALESCE(rl.limit_scope, 'no scope recorded') ORDER BY distinct_key_count DESC NULLS FIRST, scope_category ASC NULLS LAST
The agents' own records, as the role play wrote them; only the personal data of the person who ran it is redacted
Report request from Noah Fischer (analyst for the Chief Information Security Officer):
Title: Scope tally across all 76 long-lived (4+ year) active API keys
Question: Of all 76 active API keys that are 4+ years old, how many actually carry the broad 'admin_api' rate-limit scope versus no scope recorded at all — the full count, not just the 50 printed last night?
Grain: one row per distinct limit_scope value (including a 'no scope recorded' category for keys with no matching rate_limits row)
Columns:
- scope category ('admin_api', any other distinct limit_scope values found, or 'no scope recorded')
- distinct key count (count distinct api_keys.id, not rate_limits rows)
- share of the 76 keys (%)
- distinct tenants represented
Details: Source: api_keys where status = 'active' and created_at < (2026-01-05 minus 4 years) — the same 76-key population as last night's detail report — left-joined to rate_limits on api_key_id. Group by rate_limits.limit_scope (treat null, i.e. no matching rate_limits row, as its own category 'no scope recorded'). Count DISTINCT api_keys.id per group so a key is not double-counted if it somehow has more than one rate_limits row. Order by distinct key count descending, scope category as tie-break.
Check your query with the warehouse's dry_run tool, then hand it in with submit.dry_runSELECT COALESCE(rl.limit_scope, 'no scope recorded') AS scope_category, COUNT(DISTINCT ak.id) AS distinct_key_count, ROUND(COUNT(DISTINCT ak.id) * 100.0 / 76, 1) AS share_pct, COUNT(DISTINCT ak.tenant_id) AS distinct_tenants FROM ( SELECT id, tenant_id FROM api_keys WHERE status = 'active' AND created_at < DATE '2022-01-05' ) ak LEFT JOIN rate_limits rl ON rl.api_key_id = ak.id GROUP BY COALESCE(rl.limit_scope, 'no scope recorded') ORDER BY distinct_key_count DESC, scope_category ASC
STATUS: COMPILES (dry run on the empty schema, no data read) COLUMNS: scope_category, distinct_key_count, share_pct, distinct_tenants
submitSELECT COALESCE(rl.limit_scope, 'no scope recorded') AS scope_category, COUNT(DISTINCT ak.id) AS distinct_key_count, ROUND(COUNT(DISTINCT ak.id) * 100.0 / 76, 1) AS share_pct, COUNT(DISTINCT ak.tenant_id) AS distinct_tenants FROM ( SELECT id, tenant_id FROM api_keys WHERE status = 'active' AND created_at < DATE '2022-01-05' ) ak LEFT JOIN rate_limits rl ON rl.api_key_id = ak.id GROUP BY COALESCE(rl.limit_scope, 'no scope recorded') ORDER BY distinct_key_count DESC, scope_category ASC
Submitted to tonight's batch. Your work on this request is done.