You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Encode bookmark id before calling DELETE /bookmarks/{id} #74
If the route param decodes %2F, an id like lists%2F<id> or ..%2Ffeeds%2Fcustom%2F<id> would send the DELETE to a different Public API endpoint (bookmark folders, custom feeds, profile stack/experiences).
It can't be exploited by anyone else: the session cookie is SameSite=Lax and the call only uses the signed-in user's own token. Still, it's worth hardening.
Steps to reproduce
Sign in (real mode)
Send DELETE /api/bookmarks/lists%2F<listId> from the same browser
The server calls DELETE https://api.daily.dev/public/v1/bookmarks/lists/<listId> instead of a bookmark delete
Expected behavior
Only bookmark deletes should be possible through this route:
and/or reject ids that don't match /^[\w-]+$/ in the route.
Which mode?
Real mode (signed in)
Environment
No response
Anything else?
Two smaller suggestions while you're there:
Loading bookmarks fetches up to 1000, which is 20 API requests per load. Free accounts get 200 requests a month, so it's worth mentioning in the About that playing uses API quota, or lowering the cap.
Now that "Sign in with daily.dev" works, consider removing the "paste an API token" fallback so personal tokens don't pass through a hosted server.
Thanks for the careful review, and for the kind words! All three points are addressed and deployed:
Bookmark id (fix(api): only allow bookmark ids in DELETE /api/bookmarks/:id #76):DELETE /api/bookmarks/:id now rejects any id that doesn't match ^[\w-]+$ with a 400 before calling daily.dev, and deleteBookmark() also uses encodeURIComponent. Covered by e2e tests (lists%2F…, ..%2Ffeeds%2F…); on production, DELETE /api/bookmarks/lists%2F<id> now returns 400 Invalid bookmark id.
API quota (feat(roulette): play real bookmarks one page at a time, oldest-ward #77, docs(marketplace): quota-aware skill and an updated listing #79): the roulette loads one page of 50 (one request) instead of up to 1000. Clearing a batch moves on to the next, older page, and a later visit resumes there, so a visit costs 2 requests (profile + one page) plus 1 per delete. The agent skill does the same: one page per batch, more only on request, and it treats a 429 as a possible monthly quota (honours retry-after, never loops). The marketplace About now has an "API quota" section explaining this.
Token fallback (feat(auth): make the deployed app OAuth-only #78): the deployed app is OAuth-only. The "paste an API token" form and POST /api/auth only exist under pnpm dev, since OAuth can't redirect to localhost; in production builds the code is gone and the endpoint returns 404.
I'll update the marketplace listing with the new About and SKILL.md shortly.
Activity
fix(api): only allow bookmark ids in DELETE /api/bookmarks/:id (#76)
feat(roulette): play real bookmarks one page at a time, oldest-ward (#77
feat(auth): make the deployed app OAuth-only (#78)
docs(marketplace): quota-aware skill and an updated listing (#79)
finallyjay commentedon Oct 9, 2026
Thanks for the careful review, and for the kind words! All three points are addressed and deployed:
DELETE /api/bookmarks/:idnow rejects any id that doesn't match^[\w-]+$with a 400 before calling daily.dev, anddeleteBookmark()also usesencodeURIComponent. Covered by e2e tests (lists%2F…,..%2Ffeeds%2F…); on production,DELETE /api/bookmarks/lists%2F<id>now returns400 Invalid bookmark id.retry-after, never loops). The marketplace About now has an "API quota" section explaining this.POST /api/authonly exist underpnpm dev, since OAuth can't redirect to localhost; in production builds the code is gone and the endpoint returns 404.I'll update the marketplace listing with the new About and SKILL.md shortly.