Repository navigation
Fix five verified security findings from the audit - #24
Open
vijaythecoder wants to merge 8 commits into
Open
vijaythecoder wants to merge 8 commits into
vijaythecoder wants to merge 8 commits into
Conversation
Header names are now validated against RFC 5322 ftext (alphanumerics and hyphens only) in SendEmailRequest, covering both the API and dashboard send paths, and MimeMessageBuilder refuses to emit any custom header whose name or value contains CR or LF as defense in depth. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The SES webhook now stores the TopicArn from the first confirmed SNS subscription on the source and rejects any later envelope — confirmation or notification — signed for a different topic, so AWS-signed messages from an attacker's own SNS topic can no longer forge delivery or bounce events. Envelopes whose Timestamp is older than 15 minutes, more than 5 minutes in the future, or unparseable are rejected as replays. All rejections are logged to WebhookLog with status "rejected". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bootstrap/app.php no longer calls trustProxies(at: '*'), which let any client control $request->ip() via X-Forwarded-For. Operators behind a reverse proxy list it in the new TRUSTED_PROXIES env variable (comma-separated IPs/CIDRs, documented in .env.example, default none). The Fortify login limiter now keys on the socket address (REMOTE_ADDR), matching the existing larasend-api-ip limiter, so rotating forwarded headers can no longer reset the per-email login throttle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A user's active workspace now resolves to a workspace they own before
falling back to membership order (both in ProjectContext::workspaceFor
and the HandleInertiaRequests settings navigation), so being added to
someone else's lower-id workspace can no longer silently replace their
entire web context. Users can also now remove themselves from any
workspace they do not own via DELETE /workspace/{workspace}/membership.
The invitation flow for new users is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The activity export now runs recipient email, subject, and template slug through the same formulaSafe() guard the suppression export already uses, so attacker-controlled values can no longer execute as spreadsheet formulas when the CSV is opened in Excel or similar tools. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
composer audit in the quality CI job flagged known CVEs in laravel/framework, league/commonmark, league/flysystem, symfony/http-foundation, and symfony/yaml. Updates those packages (and their transitive dependencies) within existing composer.json constraints; the full test suite passes against the new versions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
laravel/framework 13.37 registers the HTTP QUERY verb on redirect routes, and Wayfinder 0.1.20 generated TypeScript for it that its own runtime types rejected, failing vue-tsc in the quality CI job. Updates laravel/wayfinder to 0.1.23 (whose Method type includes "query"), which required bumping laravel/boost and its laravel/mcp and laravel/roster dependencies. vue-tsc, composer audit, and the full test suite pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
npm audit fix plus bumping the Tiptap packages to 3.32.0 clears every advisory in production dependencies (including the high-severity @tiptap/core XSS/ReDoS advisories and the critical shell-quote issue). The remaining high finding, braces GHSA-vfj7-8cjw-p6xm, is dev-only (reached via @vue/eslint-config-typescript's lint tooling), affects all published versions with no fix, and its forced remediation downgrades the eslint config below the defineConfigWithVueTs API this repo uses — so the CI audit step now runs with --omit=dev, documented inline. Format, lint, types, build, and the full test suite all pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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
Implements fixes for the five findings verified in the recent security audit, one commit per finding, each covered by new Pest feature tests.
HIGH — MIME header injection via CRLF in custom header names.
SendEmailRequestnow requires header names to match RFC 5322 ftext (/^[A-Za-z0-9-]+$/) in addition to the reserved-name blocklist, covering both the API and dashboard send paths. As defense in depth,MimeMessageBuilder::build()rejects any custom header whose name or value contains CR or LF.MEDIUM — SNS webhook accepted AWS-signed messages from any AWS account. New nullable
sns_topic_arncolumn onsources; the TopicArn from the first confirmed SNS subscription is pinned (first confirmation wins) and any later envelope — confirmation or notification — signed for a different topic is rejected. Envelopes with a Timestamp older than 15 minutes, more than 5 minutes in the future, or unparseable are rejected as replays. All rejections are logged toWebhookLogwith statusrejected.MEDIUM — login throttle bypass via
trustProxies(at: '*'). Trusted proxies are now configured via a newTRUSTED_PROXIESenv variable (comma-separated IPs/CIDRs, default none, documented in.env.example), and the Fortify login limiter keys on the socket address (REMOTE_ADDR), matching the existinglarasend-api-iplimiter, so rotatingX-Forwarded-Forvalues can no longer reset the throttle.MEDIUM — workspace-context hijack via consentless member attachment. The active workspace now resolves to a workspace the user owns before falling back to membership order (in both
ProjectContext::workspaceFor()and theHandleInertiaRequestssettings navigation), and users can remove themselves from workspaces they don't own via the newDELETE /workspace/{workspace}/membershipendpoint. The invitation flow for new users is unchanged.LOW — CSV formula injection in the activity export. Recipient email, subject, and template slug now pass through the same
formulaSafe()guard the suppression export already uses.Reviewer notes
TRUSTED_PROXIESto the proxy's IP/CIDR; the app no longer trusts all proxies by default.add_sns_topic_arn_to_sources_table).🤖 Generated with Claude Code