Summary
Developer API read endpoints need abuse-prevention hardening. During a dev Cloud Run investigation, one client appeared to repeatedly poll the first page of a user's Developer API conversations for many hours/days using a valid authenticated API surface.
This issue tracks product/security improvements to prevent, detect, and respond to Developer API read abuse without exposing raw credentials or user content in logs.
Incident signal that motivated this
Observed in dev Cloud Run backend request logs:
- Source IP:
45.92.45.62
- User agent:
Python-urllib/3.12
- Endpoint:
GET /v1/dev/user/conversations?limit=20
- Status:
200
- Response size: consistently
21034
- No
offset observed in sampled requests
- Roughly ~1.3k successful reads/hour for sustained periods
- Jun 30 sample window covered about
2026-06-30T07:31:10Z through 2026-06-30T22:48:24Z
- Additional day-level checks suggested similar volume on Jun 25-30 in dev
- Same IP/UA pattern was not observed in prod Developer API logs for Jun 30 in the checked query
Current interpretation: likely one compromised or abused Developer API credential repeatedly polling the same conversations page. Request logs alone cannot prove the exact uid, app_id, or key_id because the Cloud Run request log does not include sanitized auth identity.
Current gaps
Code areas:
backend/routers/developer.py
backend/dependencies.py
backend/database/dev_api_key.py
backend/utils/rate_limit_config.py
backend/utils/other/endpoints.py
Gaps found:
- Developer API conversation reads are scope-gated but not sufficiently rate-limited.
GET /v1/dev/user/conversations depends on get_uid_with_conversations_read.
POST /v1/dev/user/conversations already uses with_rate_limit(..., "dev:conversations").
- Existing
"dev:conversations": (25, 3600) policy is applied to writes, not list reads.
- Read dependencies collapse Developer API auth context down to
uid.
- API key auth has
uid, scopes, app_id, and key_id.
- Route dependencies often return only
uid, so route code and rate-limit keys lose app_id/key_id attribution.
- Request logs do not contain enough sanitized identity to identify the abused key/account after the fact.
- No alerting/dashboard appears to detect repeated same-page Developer API polling.
- Sensitive read options such as full transcript access should have separate, stricter controls.
Proposed improvements
1. Add read rate limits for Developer API endpoints
Add separate policies for sensitive reads, for example:
dev:conversations_read
dev:conversation_detail_read
dev:conversation_transcript_read
dev:memories_read
dev:action_items_read
dev:goals_read
Apply them to all GET /v1/dev/user/* routes that return user data, not only writes.
2. Rate-limit by Developer API key identity
Prefer a rate-limit key like:
app_id:key_id when Developer API auth is present
- fallback to
uid only when key identity is unavailable
This prevents one user/app/key from consuming an entire account-level bucket and makes abuse attribution precise.
3. Preserve sanitized auth context through dependencies
Add auth dependencies that return ApiKeyAuth / product authorization context instead of only uid for Developer API routes that need:
Keep existing uid-only dependencies where they are still appropriate, but reads that need audit/rate-limit attribution should receive the full sanitized context.
4. Add sanitized audit logs for Developer API calls
Log structured fields such as:
- operation/path
- status
uid
app_id
key_id
- remote IP
- user agent
- limit/offset
include_transcript
- returned count / coarse response metadata
Never log:
- raw API keys
- authorization headers
- raw transcript text
- raw memory/conversation/action item content
- full response bodies
5. Add alerts and dashboards
Alert on suspicious Developer API read behavior, for example:
- high read volume per
key_id, app_id, uid, or IP
- repeated polling of the same endpoint/query (
limit=20 with no offset)
- unusually constant response size over many successful requests
- high
include_transcript=true volume
- Python/urllib or other generic scripted clients making sustained reads
6. Add emergency response controls
Provide an operator runbook and/or tooling to:
- identify the implicated Developer API key from sanitized logs
- revoke/rotate a specific key without affecting unrelated keys
- temporarily deny an IP/user-agent at the edge if still active
- communicate impact based on
uid/app_id/key_id evidence
7. Tighten sensitive data access semantics
Consider separate scopes and stricter limits for:
- conversation metadata reads
- conversation detail reads
- transcript reads (
include_transcript=true)
- bulk export-like access
Also consider maximum page size / export-window controls where needed.
8. Add regression tests
Add tests that ensure:
- every Developer API user-data read route has a rate-limit policy
- conversation transcript reads consume a stricter policy
- rate-limit keys prefer
app_id:key_id
- route-level audit helpers do not log raw content or credentials
- dependency changes preserve scope enforcement
Acceptance criteria
Notes
A candidate local patch was prototyped in a separate worktree/branch named dev-api-read-limits, but this issue should be treated as the tracking item for the full prevention/remediation work.
Summary
Developer API read endpoints need abuse-prevention hardening. During a dev Cloud Run investigation, one client appeared to repeatedly poll the first page of a user's Developer API conversations for many hours/days using a valid authenticated API surface.
This issue tracks product/security improvements to prevent, detect, and respond to Developer API read abuse without exposing raw credentials or user content in logs.
Incident signal that motivated this
Observed in dev Cloud Run
backendrequest logs:45.92.45.62Python-urllib/3.12GET /v1/dev/user/conversations?limit=2020021034offsetobserved in sampled requests2026-06-30T07:31:10Zthrough2026-06-30T22:48:24ZCurrent interpretation: likely one compromised or abused Developer API credential repeatedly polling the same conversations page. Request logs alone cannot prove the exact
uid,app_id, orkey_idbecause the Cloud Run request log does not include sanitized auth identity.Current gaps
Code areas:
backend/routers/developer.pybackend/dependencies.pybackend/database/dev_api_key.pybackend/utils/rate_limit_config.pybackend/utils/other/endpoints.pyGaps found:
GET /v1/dev/user/conversationsdepends onget_uid_with_conversations_read.POST /v1/dev/user/conversationsalready useswith_rate_limit(..., "dev:conversations")."dev:conversations": (25, 3600)policy is applied to writes, not list reads.uid.uid,scopes,app_id, andkey_id.uid, so route code and rate-limit keys loseapp_id/key_idattribution.Proposed improvements
1. Add read rate limits for Developer API endpoints
Add separate policies for sensitive reads, for example:
dev:conversations_readdev:conversation_detail_readdev:conversation_transcript_readdev:memories_readdev:action_items_readdev:goals_readApply them to all
GET /v1/dev/user/*routes that return user data, not only writes.2. Rate-limit by Developer API key identity
Prefer a rate-limit key like:
app_id:key_idwhen Developer API auth is presentuidonly when key identity is unavailableThis prevents one user/app/key from consuming an entire account-level bucket and makes abuse attribution precise.
3. Preserve sanitized auth context through dependencies
Add auth dependencies that return
ApiKeyAuth/ product authorization context instead of onlyuidfor Developer API routes that need:uidapp_idkey_idKeep existing uid-only dependencies where they are still appropriate, but reads that need audit/rate-limit attribution should receive the full sanitized context.
4. Add sanitized audit logs for Developer API calls
Log structured fields such as:
uidapp_idkey_idinclude_transcriptNever log:
5. Add alerts and dashboards
Alert on suspicious Developer API read behavior, for example:
key_id,app_id,uid, or IPlimit=20with no offset)include_transcript=truevolume6. Add emergency response controls
Provide an operator runbook and/or tooling to:
uid/app_id/key_idevidence7. Tighten sensitive data access semantics
Consider separate scopes and stricter limits for:
include_transcript=true)Also consider maximum page size / export-window controls where needed.
8. Add regression tests
Add tests that ensure:
app_id:key_idAcceptance criteria
GETendpoints are rate-limited.uid/app_id/key_idattribution for Developer API reads.Notes
A candidate local patch was prototyped in a separate worktree/branch named
dev-api-read-limits, but this issue should be treated as the tracking item for the full prevention/remediation work.