What the audit touches.
What it refuses to touch.
The live audit sends an HTTP request to a host that a visitor chooses. That is a server-side request to an address someone else picked, so it is built like an attack surface, not like a fetch helper. This page is the rulebook: what is read, what is refused before any connection exists, what is kept, and what is deliberately out of scope.
Six requests at most. Nothing else leaves the server.
One audit is: the page you named, up to three redirect hops if the site insists, then robots.txt and sitemap.xml on the same host if the time budget allows. Six requests is the hard ceiling. There is no crawler behind the form.
| Signal | Source | Reading |
|---|---|---|
| Security headers | Response headers of that single GET |
Whether CSP, HSTS, X-Content-Type-Options, frame and referrer policies are declared. It does not prove they are correctly scoped. |
| TLS parameters | The handshake of the same connection | Protocol version, cipher, issuer, days to expiry. It does not rate the configuration beyond that. |
| HTML size | Bytes counted while the body streams | How much markup is sent and whether it is compressed. The body itself is counted and discarded, never parsed or stored. |
| robots and sitemap | One GET each, presence only |
Status code and byte count. Content is not read past the first 16 KB, which is not kept either. |
| Field performance | Chrome UX Report API, only when a key is configured | Real-user p75 for LCP, CLS and INP. If the origin has no field data, the report says unavailable instead of showing a number from somewhere else. |
Six things the audit will not do.
These are not vague promises about good behaviour: each one is either refused by code before a connection is opened, or absent from the code entirely.
GET per URL, and your own rate limit stops a second one for a minute.POST, PUT or DELETE to the target. It cannot submit a form, trigger a job, or write anything to a system it does not own.robots.txt and sitemap.xml, no discovery of subdomains, no enumeration of paths. The URL you typed plus those two well-known files is the entire surface.Every limit, with its number.
These values live in netlify/lib/net-guard.js and netlify/lib/audit-probe.js, and a test suite asserts them on every deploy.
- Scheme
- http, https
- Ports
- 80, 443
- Redirects
- 3, re-validated
- Timeout
- 5 s total
- Body cap
- 512 KB
- Compressed cap
- 1 MB
- Rate limit
- 5 / min · 50 / day
- Concurrency
- 3 in flight
- Request size
- 2 KB
- Runs in
- Netlify Function
| 10.0.0.0/8 | private |
|---|---|
| 172.16.0.0/12 | private |
| 192.168.0.0/16 | private |
| 127.0.0.0/8 | loopback |
| 169.254.0.0/16 | link-local — cloud metadata lives here |
| 0.0.0.0/8 | this network |
| 100.64.0.0/10 | carrier-grade NAT |
| 192.0.0.0/24 · 198.18.0.0/15 | reserved · benchmarking |
| 224.0.0.0/4 · 240.0.0.0/4 | multicast · reserved |
| ::1/128 · ::/128 | loopback · unspecified |
| fe80::/10 | link-local |
| fc00::/7 | unique local |
| ff00::/8 | multicast |
| 2001:db8::/32 · 2002::/16 | documentation · 6to4 |
| 64:ff9b::/96 · ::ffff:0:0/96 | NAT64 and IPv4-mapped, judged by the IPv4 inside |
302 to a metadata address is stopped at the hop instead of after it.What is kept, and for how long.
Short answer: no record of your audit survives it. The long answer is the table.
| Data | Where | Lifetime |
|---|---|---|
| The URL you type | Memory of one function call | Until the response is written — seconds. It is not written to logs, not cached, and not sent to analytics. |
| Query string in that URL | Same request only | Never logged. Audit log lines contain the outcome, status, duration and byte count — no URLs, no parameters, no hostnames. |
| Your IP address | In-memory counter, as a rate-limit key | Cleared with the counters within 24 hours, per instance. Never logged, never shown in a report, never joined to anything. |
| The target's HTML | Nowhere | Counted to the 512 KB cap while streaming and discarded. It is not buffered for analysis, so there is nothing to store. |
| Cookies, accounts, sessions | None | The audit has no session, no login and no cookie jar. There is nothing to attach a report to. |
| Page analytics | Self-hosted Umami, like the rest of this site | No cookies, no cross-site identifiers, no personal data. The audit form itself is not instrumented. |
Aggregates, or nothing.
/status shows what my own services do, without showing the services.
Published
- Uptime over a rolling 30-day window, as a percentage.
- p50 and p95 response time, in milliseconds.
- Requests per day.
- Backup state —
ok,failorunknown— with the date of the last check. - Incidents: date and duration only.
Withheld
- Hostnames, IPs, ports, internal addresses.
- Service and product names that describe the stack.
- Log lines and per-request records.
- Anything belonging to a client — including whether a given client exists.
This is enforced, not promised: the snapshot has a closed schema, and a field that is not on the list fails validation instead of being published. The refresh interval is five minutes, and a page that cannot obtain fresh data says no data rather than showing yesterday's green.
Where it stops working.
A security page that only lists strengths is marketing. These are the real boundaries.
| Limit | Consequence |
|---|---|
| Rate-limit counters live in one function instance | Netlify may run several. The published limit is a floor, not a hard ceiling — a determined caller can get more than five per minute across instances. The cap exists to keep the endpoint from being a free load generator, not to run a quota business. |
| The audit reads what a server says about itself | Headers can be missing, misconfigured, or deliberately wrong. A grade is a statement about declarations, not about the safety of the application behind them. |
| Authenticated areas are not tested | Everything behind a login is out of scope by design. There is no way to audit it without credentials, and I do not accept credentials for this feature. |
| Field data requires a CrUX key | When no key is configured, the report says unavailable. It does not substitute lab numbers, and it does not show an old measurement as if it were current. |
| No history is kept | Two audits a week apart are two independent readings. Nothing is compared over time on your behalf, because nothing is stored on your behalf. |
| IPv6 reachability | The filter judges IPv6 addresses too; a target that is only reachable over IPv6 is audited normally, but an IPv6 address that embeds a blocked IPv4 address is refused like the IPv4 itself. |
Found a hole?
If you can bypass the address filter, make the endpoint fetch something it should not, or get an address into a report or a log line, that is a real finding and I want it. Include the URL you used, the time in UTC, and what you expected the filter to do.
Reports about this endpoint are read before anything else. Please do not test against third-party hosts through the form while doing it — a bypass that works by hammering someone else's server is not a proof I can use.
- Contact
- maingaidar [at] gmail.com
- Machine readable
- security.txt
- Scope
- /audit, /status, this site
- Out of scope
- third-party hosts, denial of service, social engineering
- Disclosure
- agreed before publication