About security-trust
A remediation skill for IsAgentReady.com’s Security & Trust checks. It guides site operators through correcting security headers, API CORS, WebMCP definitions, form behavior, and OAuth metadata, with verification commands.
Key features
- 01Fixes HTTPS and security headers
- 02Configures API CORS policy
- 03Checks WebMCP tool definitions
- 04Reviews risky form auto-submit
- 05Publishes OAuth metadata and auth guidance
- 06Provides read-only verification commands
Use cases
- 01Resolve failed Security & Trust scan checks
- 02Add missing headers to a web server
- 03Restrict API access by origin
- 04Prepare site authentication for agents
MCP support
Covers security checks for WebMCP tool definitions and agent authentication readiness; it is a remediation skill, not an MCP server.
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ bartwaardenburg/ isagentready-skills --skill security-trustAfter installing, type/security-trustin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/checkpoints.mdgotchas.mdsecurity-headers.mdserver-configs.mdDetails
From the project READMESecurity & Trust
Fixes the Security & Trust category of IsAgentReady.com. These checkpoints test the security baseline that agent protocols need, and the auth metadata that agents use to sign in.
- Methodology version:
2026-10-22. Methodology: https://isagentready.com/en/methodology - Scoring (weights and points): https://isagentready.com/api/v2/methodology/2026-10-22/scoring
- Full checkpoint data (stage, evidence type, verify command, rescan command): references/checkpoints.md
When to Use
- The scan shows failures in Security & Trust (legacy ids 5.x).
- HTTPS, HSTS, CSP or other security headers are missing.
- The public API needs a correct CORS policy.
- WebMCP tool definitions contain secrets or auto-submit risky forms.
- The site has a login and agents must find the OAuth metadata.
When NOT to Use
- robots.txt or crawler access: use
ai-content-discovery. - JSON-LD: use
structured-data. - Semantic HTML: use
content-semantics. - MCP, A2A or OpenAPI documents: use
agent-protocols.
Instructions
- Get the failing checkpoints from the scan. Each result has a legacy id (
5.3) and a stable id (ia.hsts). - For the header checkpoints (5.1 to 5.9), use one server configuration from references/server-configs.md. It fixes all headers together.
- For the other checkpoints, go to the fix workflow with the anchor that is equal to the stable id.
- Replace
example.comwith the domain of the site. Run the verify command. All verify commands are read-only. - Rescan with
isagentready results <domain> --checkpoint <stable-id>or at isagentready.com.
If $ARGUMENTS is provided, use it as the URL to fix or as the checkpoint to fix.
Checkpoints
Strength is the agentready.org spec level (MUST, SHOULD, MAY). Strength does not change the score.
| Legacy | Stable ID | Name | AR IDs | Strength |
|---|---|---|---|---|
| 5.1 | ia.https | HTTPS | none | MUST |
| 5.3 | ia.hsts | HSTS | none | MUST |
| 5.4 | ia.csp | Content-Security-Policy | none | MUST |
| 5.5 | ia.x-content-type-options | X-Content-Type-Options | none | MUST |
| 5.6 | ia.frame-protection | X-Frame-Options / frame-ancestors | none | MUST |
| 5.7 | ia.cors | CORS | none | MAY |
| 5.9 | ia.referrer-policy | Referrer-Policy | none | MUST |
| 5.10 | ia.tool-definition-security | Tool definition security | none | MAY |
| 5.11 | ia.auto-submit-risk | Auto-submit risk | none | MAY |
| 5.12 | ia.oauth-discovery | OAuth discovery | AR-ACT-01 | SHOULD |
| 5.13 | ia.oauth-protected-resource | OAuth protected resource | AR-ACT-01 | SHOULD |
| 5.14 | ia.agent-auth-readiness | Agent auth readiness | AR-ACT-01 | SHOULD |
All Headers at Once
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'none'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Use always, so that Nginx also sends the headers on 3xx, 4xx and 5xx responses. Configurations for Apache, Caddy, Vercel, Netlify, Cloudflare, Express, Next.js and Django are in references/server-configs.md.
Verify all headers: curl -sfI https://example.com/ | grep -iE '^(strict-transport|content-security|x-content-type|x-frame|referrer-policy)'
Fix Workflows
5.1 HTTPS
Passes when the final URL after redirects uses https:// with a valid certificate.
- Get a certificate. With Let's Encrypt and Nginx:
sudo certbot --nginx -d example.com -d www.example.com. - Redirect HTTP to HTTPS:
server { listen 80; server_name example.com; return 301 https://$host$request_uri; }
Verify: curl -sfI https://example.com/ | head -1
5.3 HSTS
Passes when Strict-Transport-Security has max-age of 31536000 or more. includeSubDomains is better. A short max-age gives partial credit.
- Add the header:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - Add
preloadand submit the domain at hstspreload.org when all subdomains use HTTPS.
Verify: curl -sfI https://example.com/ | grep -i '^strict-transport-security'
5.4 Content-Security-Policy
Passes when the CSP has real directives. A CSP with only upgrade-insecure-requests gives partial credit.
- Start in report-only mode to find the sources that the site needs:
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' https://www.googletagmanager.com; report-uri /csp-report" always; - Change to
Content-Security-Policywhen the reports are clean. See references/security-headers.md for nonces.
Verify: curl -sfI https://example.com/ | grep -i '^content-security-policy'
5.5 X-Content-Type-Options
Passes when the value is exactly nosniff.
- Add the header:
add_header X-Content-Type-Options "nosniff" always;
Verify: curl -sfI https://example.com/ | grep -i '^x-content-type-options: nosniff'
5.6 X-Frame-Options / frame-ancestors
Passes when X-Frame-Options is DENY or SAMEORIGIN, or the CSP has frame-ancestors.
- Add
frame-ancestors 'none'to the CSP, oradd_header X-Frame-Options "DENY" always;. - When trusted sites must embed the page, use
frame-ancestors 'self' https://partner.example. Do not useALLOW-FROM.
Verify: curl -sfI https://example.com/ | grep -iE '^x-frame-options|frame-ancestors'
5.7 CORS
Applies to the public API operation that 4.19 verifies. Passes when preflight and GET give matching Access-Control-Allow-* headers, no wildcard with credentials and Vary: Origin for a dynamic origin.
- Answer the preflight and the GET with the same policy:
const allowed = new Set(["https://app.example.com", "https://agent.example"]); app.use("/api", (req, res, next) => { const origin = req.get("Origin"); if (allowed.has(origin)) res.set({ "Access-Control-Allow-Origin": origin, Vary: "Origin" }); res.set({ "Access-Control-Allow-Methods": "GET", "Access-Control-Allow-Headers": "Accept" }); return req.method === "OPTIONS" ? res.sendStatus(204) : next(); }); - For a public API without cookies,
Access-Control-Allow-Origin: *is correct. Never combine*withAccess-Control-Allow-Credentials: true.
Verify: curl -sI -H 'Origin: https://agent.example' https://example.com/api | grep -iE '^(access-control-|vary)'
5.9 Referrer-Policy
Passes when Referrer-Policy is present and is not unsafe-url.
- Add the header:
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Verify: curl -sfI https://example.com/ | grep -i '^referrer-policy'
5.10 Tool definition security
Applies when the page has WebMCP tool definitions. Passes when the definitions contain no secrets (JWT, API keys, tokens, card numbers, passwords), the names match the descriptions, and read-only tools have readOnlyHint.
- Remove each token or key from
toolname,tooldescriptionandregisterTool()code. Load secrets on the server. - Mark tools that do not change data:
document.modelContext?.registerTool({ name: "search_products", description: "Search the product catalog by keyword", annotations: { readOnlyHint: true }, inputSchema: { type: "object", properties: { query: { type: "string" } }, required: ["query"] }, execute: async ({ query }) => searchProducts(query), });
Verify: curl -sf https://example.com/ | grep -ciE 'tool(name|description)="[^"]*(token|password|secret|api[_-]?key)' (expect 0)
5.11 Auto-submit risk
Applies when the page has forms. Passes when no form has toolautosubmit, or only search and filter forms have it. Risky actions give partial credit. Password or card fields with auto-submit fail.
- Remove
toolautosubmitfrom login, payment, delete and send forms. Keep it on search forms:<form action="/search" toolname="search_products" tooldescription="Search the catalog" toolautosubmit> <input name="q" toolparamdescription="Search keywords"> </form>
Verify: curl -sf https://example.com/ | grep -oE '<form[^>]*toolautosubmit[^>]*>' (expect only search or filter forms)
5.12 OAuth discovery
Applies when the site has auth signals. Passes when /.well-known/oauth-authorization-server or /.well-known/openid-configuration has issuer, authorization_endpoint and token_endpoint.
- Publish the metadata (RFC 8414):
{ "issuer": "https://example.com", "authorization_endpoint": "https://example.com/oauth/authorize", "token_endpoint": "https://example.com/oauth/token", "code_challenge_methods_supported": ["S256"], "scopes_supported": ["read", "write"] }
Verify: curl -sf https://example.com/.well-known/oauth-authorization-server | jq -e '.issuer and .authorization_endpoint and .token_endpoint'
5.13 OAuth protected resource
Applies when the site has auth signals. Passes when /.well-known/oauth-protected-resource has resource and authorization_servers, or the homepage sends WWW-Authenticate.
- Publish the metadata (RFC 9728):
{ "resource": "https://example.com/api", "authorization_servers": ["https://example.com"], "scopes_supported": ["read"] } - On a 401 from the API, send
WWW-Authenticate: Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource".
Verify: curl -sf https://example.com/.well-known/oauth-protected-resource | jq -e '.resource and (.authorization_servers | length > 0)'
5.14 Agent auth readiness
Applies when the site has an auth surface. The check combines PKCE S256, scopes metadata, protected resource metadata or a WWW-Authenticate header, a valid /auth.md and an agent-safe grant.
- Add
"code_challenge_methods_supported": ["S256"]andscopes_supportedto the metadata from 5.12. - Publish 5.13.
- Write
/auth.md:# Authentication - Flow: OAuth 2.1 authorization code with PKCE (S256) - Agents: use the device code grant or a user-approved token. Do not ask for passwords. - Scopes: read (default), write (needs user approval)
Verify: curl -sf https://example.com/.well-known/oauth-authorization-server | jq -e '.code_challenge_methods_supported | index("S256")'
Key Gotchas
- An HSTS
max-age=86400(one day) gives partial credit. Use one year. - A CSP with only
upgrade-insecure-requestsgives partial credit. - Nginx
add_headerwithoutalwaysskips error responses. Access-Control-Allow-Origin: *with credentials is invalid and unsafe.- OAuth metadata on a different domain does not count for this site.
See references/gotchas.md for correct and incorrect examples.
References
- references/checkpoints.md: generated checkpoint data for each checkpoint
- references/security-headers.md: each header, its values and its effect
- references/server-configs.md: configurations for Nginx, Apache, Caddy, Vercel, Netlify, Cloudflare, Express, Next.js and Django
- references/gotchas.md: common errors with correct and incorrect examples