mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
fix(http): refuse state changes a browser sends from another site
The session cookie is SameSite=Lax, and SameSite compares the registrable domain, so a page on a sibling subdomain of the instance could send a CORS-simple POST with the person's cookie attached. safeJson accepted any Content-Type containing "application/json", so a text/plain body that mentions it in a parameter, which needs no preflight, was parsed as the person's own request: readings added, entries deleted, integrations disconnected, a delegate invited within the re-proof window. apiHandler now refuses a POST, PUT, PATCH or DELETE before authentication when the browser marks it Sec-Fetch-Site same-site or cross-site, or, from a browser that sends no fetch metadata, when its Origin names a host other than the one the request went to or APP_URL. A request with an Authorization header, or with neither header (the phone app, scripts, webhook senders), is unaffected, as are the webhook and URL-credential routes that authenticate with their own secret. The JSON media type is compared exactly, with parameters allowed, in safeJson and in every route that branched on a substring of it.
This commit is contained in:
1 parent
fa50bcd1cb
commit
77ace106b3
20 files changed
+436
-47
No files matched your search
+23
-23
@@ -38581,29 +38581,29 @@ components:
|
||||
profile.update.invalidBody, profile.update.nothingSaved; profile_claim — profile_claim.invalid,
|
||||
profile_claim.oidc_only_unsupported, profile_claim.sso_unavailable, profile_claim.taken; record_write —
|
||||
record_write.rate_limited; report-selection — report-selection.body.invalid_json,
|
||||
report-selection.body.invalid_shape, report-selection.leaves.unknown; route — route.retired; search —
|
||||
search.invalid; security_activity — security_activity.invalid; share-link —
|
||||
share-link.document.decryptFailed, share-link.document.notFound, share-link.document.rateLimited,
|
||||
share-link.documents.invalid, share-link.report.notFound, share-link.report.rateLimited,
|
||||
share-link.selection.forbidden_leaf, share-link.selection.unknown_leaf; sharing —
|
||||
sharing.accept.expired, sharing.accept.not_found, sharing.accept.not_pending, sharing.accept.revoked,
|
||||
sharing.access.denied, sharing.invite.duplicate, sharing.invite.invalid, sharing.invite.invalid_scope,
|
||||
sharing.invite.manage_browser_only, sharing.invite.no_account, sharing.invite.refused,
|
||||
sharing.invite.self, sharing.not_permitted, sharing.renounce.already_ended, sharing.renounce.not_found,
|
||||
sharing.revoke.already_ended, sharing.revoke.not_found, sharing.session.changed, sharing.switch.invalid,
|
||||
sharing.switch.wrong_transport; source-priority — source-priority.body.invalid_json,
|
||||
source-priority.body.invalid_shape; symptoms — symptoms.definition.limitReached,
|
||||
symptoms.definition.notFound, symptoms.episode.notOpen, symptoms.event.notFound, symptoms.invalid;
|
||||
timeline — timeline.invalid; tokens — tokens.documents.ceiling_reached,
|
||||
tokens.measurements.ceiling_reached, tokens.mirror.not_measurement_token,
|
||||
tokens.workouts.ceiling_reached; vaccination — vaccination.booster-invalid,
|
||||
vaccination.booster-no-antigen, vaccination.booster-out-of-scope, vaccination.custom-vaccine-not-found,
|
||||
vaccination.custom.invalid, vaccination.custom.name-taken, vaccination.custom.not-found,
|
||||
vaccination.encounter-not-found, vaccination.identity-required, vaccination.invalid,
|
||||
vaccination.link.invalid, vaccination.not-found, vaccination.practitioner-not-found; workout —
|
||||
workout.batch.invalid, workout.batch.payload_too_large, workout.batch.source_not_permitted,
|
||||
workout.batch.too_large, workout.delete.synced_source; (unprefixed) — about_me_conflict,
|
||||
ai_response_truncated, coach_prefs_conflict, dashboard_layout_conflict, empty_file,
|
||||
report-selection.body.invalid_shape, report-selection.leaves.unknown; request — request.cross_site;
|
||||
route — route.retired; search — search.invalid; security_activity — security_activity.invalid;
|
||||
share-link — share-link.document.decryptFailed, share-link.document.notFound,
|
||||
share-link.document.rateLimited, share-link.documents.invalid, share-link.report.notFound,
|
||||
share-link.report.rateLimited, share-link.selection.forbidden_leaf, share-link.selection.unknown_leaf;
|
||||
sharing — sharing.accept.expired, sharing.accept.not_found, sharing.accept.not_pending,
|
||||
sharing.accept.revoked, sharing.access.denied, sharing.invite.duplicate, sharing.invite.invalid,
|
||||
sharing.invite.invalid_scope, sharing.invite.manage_browser_only, sharing.invite.no_account,
|
||||
sharing.invite.refused, sharing.invite.self, sharing.not_permitted, sharing.renounce.already_ended,
|
||||
sharing.renounce.not_found, sharing.revoke.already_ended, sharing.revoke.not_found,
|
||||
sharing.session.changed, sharing.switch.invalid, sharing.switch.wrong_transport; source-priority —
|
||||
source-priority.body.invalid_json, source-priority.body.invalid_shape; symptoms —
|
||||
symptoms.definition.limitReached, symptoms.definition.notFound, symptoms.episode.notOpen,
|
||||
symptoms.event.notFound, symptoms.invalid; timeline — timeline.invalid; tokens —
|
||||
tokens.documents.ceiling_reached, tokens.measurements.ceiling_reached,
|
||||
tokens.mirror.not_measurement_token, tokens.workouts.ceiling_reached; vaccination —
|
||||
vaccination.booster-invalid, vaccination.booster-no-antigen, vaccination.booster-out-of-scope,
|
||||
vaccination.custom-vaccine-not-found, vaccination.custom.invalid, vaccination.custom.name-taken,
|
||||
vaccination.custom.not-found, vaccination.encounter-not-found, vaccination.identity-required,
|
||||
vaccination.invalid, vaccination.link.invalid, vaccination.not-found,
|
||||
vaccination.practitioner-not-found; workout — workout.batch.invalid, workout.batch.payload_too_large,
|
||||
workout.batch.source_not_permitted, workout.batch.too_large, workout.delete.synced_source; (unprefixed)
|
||||
— about_me_conflict, ai_response_truncated, coach_prefs_conflict, dashboard_layout_conflict, empty_file,
|
||||
health_score_config_conflict, insights_layout_conflict, invalid_base_updated_at,
|
||||
json_carries_no_intake_time, json_not_an_array, medication_layout_conflict, missing_required_columns,
|
||||
modules_conflict, mood_tag_layout_conflict, not_configured, notification_prefs_conflict, oidc_only,
|
||||
|
||||
Reference in new issue
Block a user