form-action 'self': why the policy guards form targets as well
Every Anticode page already has forms that post only to its own /api/ paths. The page's Content-Security-Policy adds form-action 'self' anyway, and Sentinel checks that it's there. The two do different jobs: one check makes sure the forms you have are right; the directive makes the browser refuse any form that isn't, including one nobody meant to add.
What the directive does
form-action tells the browser which addresses a form on this page may submit to. With the value 'self', only the page's own origin is allowed. If any form, however it got there, tries to submit somewhere else, the browser blocks the submission and reports a policy violation. The visitor's data never leaves the page.
One detail catches people out: form-action doesn't fall back to default-src. A policy can set default-src 'self' and still allow forms to post anywhere, because form targets are governed only by their own directive. That's the reason Sentinel checks for it separately rather than trusting a strict default-src to cover it. The guide to Content Security Policy explains the other directives that behave this way.
Why a second lock is worth having
The form origin check inspects the forms that exist when the page is built and published. The policy protects the page as it actually runs in a visitor's browser, which covers situations a build-time check can't see:
- Injected markup. If content ever reached the page through a route nobody anticipated, a fake login or payment form posting to an attacker's server is a classic payload. The browser refuses to send it.
- A later edit gone wrong. A form changed after the scan, or a mistake in a hand edit, can't redirect submissions off-site.
- Stale assumptions. Checks are code, and code has edge cases. A browser-enforced rule is independent of them.
Security people call this defence in depth: several independent layers, so that one failing doesn't expose the visitor. A form-action self CSP rule is a good example of the idea, because it costs nothing on a page whose forms are already right and only ever acts when something has gone wrong. It never blocks a form that posts to the page's own origin, so there is no trade-off for normal visitors.
Where the directive lives
| Layer | Setting |
|---|---|
| The page's meta policy | form-action 'self', alongside script-src 'none' and the rest of the page's policy |
| The published site's response header | form-action 'self' again, in the header policy sent with every page |
| Sentinel, in the builder | Checks the meta policy contains form-action 'self', reported as “Form targets are locked down” |
Because the header is added when the site is served, a published page has the directive even if its own meta tag were somehow missing it.
Adding it to another site
If you run other sites, adding the directive is one of the cheapest security improvements available. List every place your forms legitimately submit to, then set form-action to exactly those: 'self' for your own server, plus the full origin of any form service you use. Test every form after the change, including search boxes and newsletter sign-ups, because a missed target simply stops working. A page with no forms at all can use form-action 'none'. The guide to security headers covers how to send policies as headers on common hosts.
Limits
- It guards the destination, not the content. The browser still sends whatever the visitor typed to the allowed origin. Validating it is the server's job, which Anticode's form handling does.
- Redirects after submission. Browsers have differed on whether
form-actionalso applies to a redirect that follows a submit. Anticode's forms answer with a thank-you page rather than a redirect, so it doesn't arise here, but don't rely on it elsewhere. - The check reads the meta tag. Sentinel's check looks for the directive in the page's own policy. The server's publish gate checks form targets directly instead.
- Apps differ. App builds don't submit forms themselves; they send through Anticode's form pipeline under their own sandbox rules.
Questions people ask
Does default-src cover form-action?
No. form-action doesn't fall back to default-src, so a policy needs it stated explicitly. That's why Sentinel checks for it on its own.
If my forms already post to my site, do I need form-action 'self'?
It's still worth having. It stops any form added later, by mistake or by an attacker, from sending data elsewhere.
What happens if a form breaks the policy?
The browser refuses to submit it and logs a policy violation. Nothing is sent.