Security
This property holds no credential, no secret and no identity truth.
It is a static content site with an acquisition handoff. It stores nothing about you, authenticates nobody, and fetches nothing at render time — so a page here cannot fail because another system is unavailable, and cannot serve a stale copy of live state under our own name.
What is left worth describing is the header set this origin sends, the build that refuses to ship a link pointing somewhere unexpected, and an honest account of what none of that establishes.
Where things live
The interesting material is somewhere else, on purpose.
| Surface | What it holds | What it does not |
|---|---|---|
| agents.ecocitizenz.com | Static content, an acquisition handoff, and a client-side check of whether an identifier is well formed. | No account, no session, no password, no API key, no payment detail, no identity evidence, and no copy of any record. |
| trustops.ecocitizenz.com | Authentication, the account, Passport issuance, capacity and commerce. Every credential-bearing interaction in this estate happens there. | Nothing about it is reachable from this property. Following a call to action is a top-level navigation, not an embedded flow. |
| ECZ-ID Core | Canonical identity truth: what is actually true about an identity, and the evidence behind it. The Resolver publishes a projection of it. | It is not addressable from this site. This property has no build-time or run-time link to it. |
| resolver.ecocitizenz.org | The public record, read-only, unauthenticated and unmetered. One place where current state is true. | No write path exists from here, and nothing on this site caches, mirrors or restates what it publishes. |
The Resolver is read-only and public by design: reads are unauthenticated, unmetered and available to anyone, including people who have no relationship with us at all. That is a deliberate property of the system rather than an oversight in it.
Response headers
What this origin sends, and why each one is what it is.
| Header | Value | Why |
|---|---|---|
| Content-Security-Policy | See the directive table below | Derived from what this site actually loads, rather than copied from a template. Every directive is either the floor or a specific concession with a reason. |
| X-Content-Type-Options | nosniff | The browser honours the declared content type instead of guessing one. A guess is how a file that is served as text ends up being executed as script. |
| Referrer-Policy | strict-origin-when-cross-origin | A site you navigate to is told which origin you came from, never which page. A path can identify an individual, and a referrer leaks it accidentally. |
| X-Frame-Options | DENY | The legacy counterpart of frame-ancestors, kept for user agents that honour only the older header. Two mechanisms saying the same thing is cheap insurance. |
| Permissions-Policy | camera=(), microphone=(), geolocation=(), payment=(), usb=() | An empty allowlist for capabilities this property has no use for. Nothing on the page, or embedded in it, can prompt you for any of them. |
| Strict-Transport-Security | max-age=63072000; includeSubDomains | Two years, subdomains included. Deliberately NOT preload: submission to the preload list is a slow-to-reverse commitment binding the whole domain, and it is the operator's decision to make explicitly rather than a side effect of a config file. |
The policy, directive by directive
The Content-Security-Policy is derived from what this site loads.
| Directive | Why it is this |
|---|---|
| default-src 'self' | The floor. Anything not named by a more specific directive may only come from this origin. |
| base-uri 'none' | Nothing may rewrite the document base. An injected base element silently re-points every relative URL on the page, including the acquisition links. |
| object-src 'none' | No plugin content. Nothing on this property needs it, and the legacy embedding surface is worth closing outright. |
| frame-ancestors 'none' | This site is never to be framed. A framed page can be dressed as a step inside somebody else's flow, which is exactly how a handoff gets impersonated. |
| form-action 'self' | A form may only submit to this origin. The TrustOps handoff is a top-level navigation from a link, which this directive does not govern. |
| script-src 'self' 'unsafe-inline' | Next.js inlines its bootstrap and flight payload as inline script. Removing 'unsafe-inline' requires per-request nonces, which requires middleware, which forces every prerendered page to become dynamic. 'unsafe-eval' is deliberately absent — no code path here builds code from a string. |
| style-src 'self' 'unsafe-inline' | next/font injects an inline style element. Same trade as above, with a smaller blast radius: a style is not an execution context. |
| img-src 'self' data: https://api.ecocitizenz.com | Exactly one remote origin, named rather than wildcarded, because it draws the Live Proof badge from current state. A wildcard on the parent domain would admit any subdomain somebody could stand up. |
| font-src 'self' | next/font self-hosts the typeface at build time, so no font origin is contacted at runtime and no third party learns who is reading. |
| connect-src 'self' | The browser may not open a request to any other origin. This is what makes the privacy statement structural rather than procedural: a third-party collector could not be reached even if one were added by mistake. |
| manifest-src 'self' | The web app manifest is served from this origin, like everything else it describes. |
| upgrade-insecure-requests | Any plaintext subresource that slipped into a template is fetched over https instead of being requested in the clear. |
The absence that matters most
'unsafe-eval' is not in the script policy and no build step needs it. Inline script is permitted because the framework emits its bootstrap that way; building executable code from a string is a different capability and one this site never uses.
Build-time preflight
A production build fails rather than ship a call to action pointing at the wrong host.
It must be a valid absolute URL
A malformed value would otherwise resolve against this origin at runtime and produce a link that goes nowhere, discovered by an operator at the worst possible moment.
It must be https
An acquisition or proof handoff sent over plaintext is one an intermediary can rewrite. There is no development exception in the shipped value.
Its host must be on an enumerated allowlist
Five hosts, listed one by one rather than matched by pattern. A wildcard on the parent domain would admit any subdomain an attacker could stand up, which defeats the point of checking at all.
The contact address must be real
It must parse, and it must not be a placeholder domain. A disclosure route that bounces is worse than one that is obviously missing.
The reason the build is willing to fail over this: a call to action pointing at an unexpected host is indistinguishable, to the person clicking it, from a hijacked one. The free Passport link is the most important link on this property, and a silently degraded handoff is invisible until a real operator follows it.
A production build throws. A development build warns loudly and carries on, so local work is never blocked by configuration that only matters at release. The defaults are the real production values, so an unset variable degrades to correct rather than to broken.
What none of this establishes
Headers constrain a browser. They are not a claim about outcomes.
No certification, no audit, no scheme
This page describes configuration you can verify yourself by reading the response headers of any page on this host. It does not assert an external assessment, a compliance standard or an accreditation, because there is none to assert.
No bug-bounty programme
There is no reward process, no scope document and no published response-time commitment. We would rather say that than invent a programme that does not exist behind the address below.
A policy is a constraint, not a promise
A restrictive policy narrows what a browser is permitted to do with this document. It is not a claim that no defect exists here or anywhere else in the estate, and no configuration is a substitute for that honesty.
And it says nothing about any agent
How this website is configured has no bearing on any agent that holds an ECZ-ID. A published record establishes identity and an operator relationship, and nothing on this page extends it.
Responsible disclosure.
If you have found something wrong with this property, write to us directly. One address, monitored, with no form in front of it.
Say which surface
This site, TrustOps, the Resolver or the badge API. They are operated as separate surfaces and a report that names the wrong one takes longer to act on.
Include the request
The URL, the method, the response you saw and the steps to reproduce it. A description of an impact without a reproduction is difficult to act on quickly.
Please do not include third-party data
Send us what demonstrates the issue, not somebody else's personal data. If a report would require it to be understood, say so and we will work out how to look at it.