Repository navigation
Security hardening: fail-closed auth, POST-only reactivation, tag endpoint fixes - #13
Merged
Merged
Conversation
Authentication - Refuse requests the web server did not authenticate (no REMOTE_USER), so an ignored .htaccess or a missing nginx auth block fails closed instead of leaving all data open. Opt out with $require_http_auth = false in config.php. - .htaccess/nginx: demand HTTPS before any password prompt, send HSTS, pass REMOTE_USER to PHP-FPM, and block helper scripts with FilesMatch, which also covers requests like queries/db.php/x (the <If> on REQUEST_URI did not). - Session cookie gets the Secure flag behind a TLS-terminating proxy. Data changes - Reactivation of due recurring entries no longer happens as a side effect of GET query-todos.php (no CSRF protection, ran for all users): it is now the POST endpoint reactivate-due.php, limited to the lists of the current user, and claims each entry in recurringCopied first so concurrent requests cannot create duplicates. - Merging a tag into itself deleted the tag and all its assignments: rejected on the server and no longer offered in the UI. Tag edit/delete/merge run in a transaction. - Tag endpoints check ownership (tag used by the current user's todos and by nobody else) and validate their parameters; a missing tag_name no longer blanks the tag name. - Data endpoints answer with application/json. Tests: regression tests for each of the above, tests/auth.test.js for the authentication check, extended tests/apache-access.sh. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeVfWCjSSQSgKKHpGbjKWK
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the findings of a security review of the app. No critical vulnerabilities were found (SQL injection, XSS and POST CSRF were checked and are fine); the findings below were verified by reproducing them against a running instance before fixing.
Authentication / deployment
.htaccess/nginx. If.htaccesswas ignored (e.g.AllowOverride None), everything was open. Requests without an authenticatedREMOTE_USERare now rejected with a 403. OnlyREMOTE_USERis trusted, not the forgeableAuthorizationheader. Opt out with$require_http_auth = false;inconfig.php..htaccessrequires HTTPS (orX-Forwarded-Proto: https) before the password prompt, so browsers never send credentials over plain HTTP. HSTS added to Apache and nginx samples; the nginx sample redirects to HTTPS. Session cookie getsSecurebehind a TLS-terminating proxy.<If>rule onREQUEST_URIwas bypassed byqueries/db.php/x. Replaced withFilesMatch, which also covers path-info requests.recurrence.phpis now blocked too.REMOTE_USERto PHP-FPM.Data changes
query-todos.phpran reactivation of recurring entries (inserts) with no CSRF protection and for all users. It is now the POST endpointreactivate-due.php(CSRF-protected, current user's lists only). Each entry is claimed inrecurringCopiedfirst inside a transaction, so concurrent requests cannot create duplicates.todo.jscalls it before loading the list.tag_nameblanked the tag name; now rejected. Endpoints usepostParaminstead of raw$_POST.application/json.Behaviour changes to be aware of
REMOTE_USER(fastcgi_param REMOTE_USER $remote_user;, now in the sample). HTTP-only setups get a 403 until they use HTTPS or sendX-Forwarded-Proto. Deployments with other protection must set$require_http_auth = false;. CI and the test docs do this.Not included
shivammathur/setup-phpto a commit SHA.config.phpout of the webroot (no custom config path support; the sample config now recommends it).Testing
npm test: 22/22 pass (API, Playwright UI, and newtests/auth.test.js, which starts its own PHP servers and needs no DB).tests/apache-access.shextended (HTTPS-first, path-info cases, HSTS); confirmed it fails against the old.htaccess.REMOTE_USERreaches PHP (401 without credentials, 200 with), and withAllowOverride Nonethe app now returns 403 instead of serving everything.npm audit --omit=dev: 0 vulnerabilities;vendor/matches the lockfile.🤖 Generated with Claude Code
https://claude.ai/code/session_01LeVfWCjSSQSgKKHpGbjKWK
Generated by Claude Code