# AAAA Lookup How the AAAA Lookup reads a name's IPv6 addresses, sorts each one by kind, names the network behind every public address, says whether IPv4 visitors are served too, and how to fix and confirm IPv6 publication. Canonical: https://docs.tamperbox.dev/tools/aaaa-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A DNS name, or AAAA records to paste Outputs: A verdict counting IPv6 and IPv4 addresses, findings, one row per address with its kind and network, and the answer as dig-style text Limitations: A published address is not proof that anything answers on it; network names come from routing registry data and can lag; pasted records get no network lookup The tool page is [tamperbox.dev/aaaa-lookup](https://tamperbox.dev/aaaa-lookup). It opens on a live lookup of `tamperbox.dev`: real global IPv6 addresses, the network that announces them, and the IPv4 addresses beside them. This page is the long version: how addresses are read and sorted, how networks are named, the findings, and how to publish IPv6 correctly.
Where processing happens: a name is sent to the Tamperbox server, which asks Cloudflare for its AAAA and A records over DNS over HTTPS, then looks up the network of each global IPv6 address. Pasted records are read in your browser with no network lookup. Sample names under .example are answered in the browser. Ordinary lookup results are not persisted by this page. An explicit handoff temporarily stores its value in session storage for one-use transfer.
## What the tool answers An AAAA record holds one IPv6 address for a name ([RFC 3596 section 2.1](https://www.rfc-editor.org/rfc/rfc3596#section-2.1)), the IPv6 counterpart of an A record. The tool answers: 1. **Does the name publish IPv6 addresses?** Every AAAA record, after any alias the resolver followed. 2. **Is each address one the internet can reach?** The classification distinguishes global addresses from documentation, local-scope and transition ranges. It does not measure routing or reachability. 3. **Who runs each address?** The network (autonomous system) that announces it. 4. **Are IPv4 visitors served too?** Whether the name also has A records. It does not connect to the addresses. A name can publish an IPv6 address on which no server listens; a connection test to the address shows that. ## Inputs ### A name `example.com`, `www.example.com`. The lookup runs when you stop typing, or on Enter. A pasted address or email address is reduced to its host or domain, and the hint names what was kept. ### Pasted records Text containing internal whitespace or a quote selects local record parsing: dig answers, zone lines or several addresses separated by newlines. A lone bare IPv6 address has neither and is treated as invalid domain input; supply a full AAAA record line for one address. Each address is sorted by kind; no network is looked up and the A records are not asked for, so the IPv4 question stays open. ### Files Drop a `.txt` file anywhere on the page. ## Reading the result ### Verdict and chips "2 IPv6 addresses for example.com, plus 2 IPv4 addresses." The line under it says who answered, or notes the documentation range for sample data. The chips say IPv6 (pass or fail) and IPv4 too, or No IPv4. ### Where your input goes Pasted records stay in the browser; a name means DNS and network lookups from our server: one AAAA query, one A query, and one network lookup per global address. ### Findings Failures first, then notes, then the passes folded. ### AAAA records One row per address: the address, its kind, and for global addresses the network name and AS number. ### DNS response The answer as dig-style text, with a copy button. ### History and Heal it History logs Break it and Heal it replacements. Revert restores the previous input; Reset input restores the first input in that sequence. Restoring a live name runs a fresh lookup. Typing starts a new history, and the log is not a monitoring record. ### Take it further The first global IPv6 address to the ASN Lookup and to Reverse DNS, and `[address]:443` to the TCP Ping, which tests whether anything answers on it. ## Method ### 1. The lookups The server asks Cloudflare for the AAAA records at the name; the resolver follows any CNAME and returns the addresses of the end ([RFC 3596 section 2.3](https://www.rfc-editor.org/rfc/rfc3596#section-2.3)). For a looked-up name it then asks for the A records, only to say whether IPv4 visitors are served too. ### 2. Sorting each address Each address is parsed (any compressed or mixed notation is accepted) and sorted by the first rule that matches: | Kind | Range | Source | | --- | --- | --- | | Unspecified: never routed | `::` | [RFC 4291 section 2.5.2](https://www.rfc-editor.org/rfc/rfc4291#section-2.5.2) | | Loopback: never routed | `::1` | [RFC 4291 section 2.5.3](https://www.rfc-editor.org/rfc/rfc4291#section-2.5.3) | | IPv4-mapped | `::ffff:0:0/96` | [RFC 4291 section 2.5.5.2](https://www.rfc-editor.org/rfc/rfc4291#section-2.5.5.2) | | Documentation range | `2001:db8::/32`, `3fff::/20` | [RFC 3849 section 4](https://www.rfc-editor.org/rfc/rfc3849#section-4), [RFC 9637 section 6](https://www.rfc-editor.org/rfc/rfc9637#section-6) | | Multicast: not a unicast host | `ff00::/8` | [RFC 4291 section 2.7](https://www.rfc-editor.org/rfc/rfc4291#section-2.7) | | Unique local: private | `fc00::/7` | [RFC 4193 section 3.1](https://www.rfc-editor.org/rfc/rfc4193#section-3.1) | | Link-local: never routed | `fe80::/10` | [RFC 4291 section 2.5.6](https://www.rfc-editor.org/rfc/rfc4291#section-2.5.6) | | NAT64 translation | `64:ff9b::/96` | [RFC 6052 section 2.1](https://www.rfc-editor.org/rfc/rfc6052#section-2.1) | | NAT64 local-use translation | `64:ff9b:1::/48` | [RFC 8215 section 1](https://www.rfc-editor.org/rfc/rfc8215#section-1) | | 6to4 transition | `2002::/16` | [RFC 3056 section 2](https://www.rfc-editor.org/rfc/rfc3056#section-2) | | Teredo transition | `2001::/32` | [RFC 4380 section 2.6](https://www.rfc-editor.org/rfc/rfc4380#section-2.6) | | Global | any other address that is publicly routable | the [IANA IPv6 special-purpose registry](https://www.iana.org/assignments/iana-ipv6-special-registry/) | | Special-purpose | any other address in that registry | | ### 3. Naming the network For each global address, the server asks the Team Cymru IP-to-ASN service over DNS (a TXT query under `origin6.asn.cymru.com` for the reversed address) for the announcing AS numbers, the prefix and the registry country, then asks for each AS's name; it also asks for the address's PTR record. The page shows the network name and the AS number. Registry data says who announces the prefix, not where a server is or who rents it; a cloud provider's network is named, not its customer. ### 4. Rules - **Not public** (fail, "address is not public"): an address sorted as unspecified, loopback, multicast, unique local, link-local or invalid, or a documentation address anywhere but the reserved sample zone. Clients that prefer IPv6 try it first: [RFC 8305 section 5](https://www.rfc-editor.org/rfc/rfc8305#section-5) has a client start "one connection attempt to a single address" and move to the next only after a delay, so an unreachable AAAA record costs every dual-stack visitor that delay. - **Translation or transition address** (info): NAT64, 6to4, Teredo, IPv4-mapped or another special-purpose address. Reachability depends on the mechanism; no network is looked up. - **IPv6 only** (info): AAAA records and no A record. Visitors on IPv4-only networks cannot reach the name. - **No IPv6** (info): no AAAA record, but A records. Visitors on IPv6-only networks reach the name only if their network translates. - **Published** (pass): N IPv6 addresses; and **IPv4 too** (pass) when A records exist. Documentation addresses on names under `.example` are the sample's and pass, labelled as sample data. ## Standards and conformance | Specification | Sections used | How the tool applies it | Where it stops | | --- | --- | --- | --- | | [RFC 3596](https://www.rfc-editor.org/rfc/rfc3596) | [2.1](https://www.rfc-editor.org/rfc/rfc3596#section-2.1), [2.3](https://www.rfc-editor.org/rfc/rfc3596#section-2.3) | AAAA records are read from the answer, after aliases | Additional-section processing does not apply to AAAA | | [RFC 4291](https://www.rfc-editor.org/rfc/rfc4291) | 2.5.2, 2.5.3, 2.5.5.2, 2.5.6, 2.7 | Address kinds are sorted by these ranges | Updated by [RFC 5952](https://www.rfc-editor.org/rfc/rfc5952) (text form) and others; output keeps the resolver's text | | [RFC 4193](https://www.rfc-editor.org/rfc/rfc4193), [RFC 3849](https://www.rfc-editor.org/rfc/rfc3849), [RFC 9637](https://www.rfc-editor.org/rfc/rfc9637), [RFC 6052](https://www.rfc-editor.org/rfc/rfc6052), [RFC 8215](https://www.rfc-editor.org/rfc/rfc8215), [RFC 3056](https://www.rfc-editor.org/rfc/rfc3056), [RFC 4380](https://www.rfc-editor.org/rfc/rfc4380) | as in the table above | Each range is a kind; private and never-routed kinds fail | RFC 3849 is updated by RFC 9637, which adds `3fff::/20` | | [RFC 8305](https://www.rfc-editor.org/rfc/rfc8305) | [4](https://www.rfc-editor.org/rfc/rfc8305#section-4), [5](https://www.rfc-editor.org/rfc/rfc8305#section-5) | Explains why a bad AAAA record hurts dual-stack visitors | No connection is attempted; obsoletes [RFC 6555](https://www.rfc-editor.org/rfc/rfc6555) | ## Finding reference | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | N IPv6 addresses published | pass | [RFC 3596 2.1](https://www.rfc-editor.org/rfc/rfc3596#section-2.1) | The name has routable IPv6 addresses | Test a connection to one | | IPv4 too | pass | | Visitors on either network find the name | None | | address is not public | fail | [RFC 4291 2.5](https://www.rfc-editor.org/rfc/rfc4291#section-2.5), [RFC 4193 3.1](https://www.rfc-editor.org/rfc/rfc4193#section-3.1) | Clients try an address nobody can reach, then fall back late or fail | Publish the global address, or remove the record | | address: translation or transition kind | info | [RFC 6052 2.1](https://www.rfc-editor.org/rfc/rfc6052#section-2.1), [RFC 3056 2](https://www.rfc-editor.org/rfc/rfc3056#section-2) | Reachability depends on the mechanism | Prefer a native global address | | IPv6 only | info | | IPv4-only visitors cannot reach the name | Add A records unless IPv6-only is intended | | No IPv6 | info | | IPv6-only visitors depend on translation | Add AAAA records if the host offers IPv6 | | No AAAA record at name | info | [RFC 2308 2.2](https://www.rfc-editor.org/rfc/rfc2308#section-2.2) | No IPv6 and no IPv4 here | Check the name and the records | | The name does not exist | fail | [RFC 2308 2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1) | No record of any kind | Check the name | | The resolver could not answer | fail | [RFC 1035 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) | Validating resolvers return nothing | Check the DNSSEC chain | ## Guide ### Add IPv6 to a site 1. Ask your host for the server's IPv6 address. Many CDNs and platforms enable it with a setting. 2. Make sure the server listens on it, on the same ports as IPv4, with the same certificate. 3. Publish the AAAA record (or let the CDN publish it), with the same TTL as the A record. 4. Look the name up here, then test a connection: the TCP Ping link opens `[address]:443`. Confirm from a terminal: `dig +short AAAA www.example.com` lists the addresses; `curl -6 -sI https://www.example.com` makes a request over IPv6 only. ### A private or documentation address is published It usually comes from a copied example (`2001:db8::1`) or from a server's internal address entered by mistake. Replace it with the global address, or delete the AAAA record: a name with only A records is fine, while a name with a broken AAAA record is slower for every dual-stack visitor. ### IPv6 only Intended for some internal or modern-only services. For a public site, add A records too, or many visitors cannot reach it at all. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | IPv6 only | a sample name with AAAA and no A | "IPv6 only" | | No IPv6 | the sample domain, which has A records only | "No IPv6" | | Name does not exist | `nohost.` in front of your name | NXDOMAIN | ## Worked example The page opens on `tamperbox.dev`, looked up live. Address counts and announcing networks are read from the current response; the exact addresses can change, which is why the page shows what Cloudflare returns now rather than a fixed list. The verdict counts both families, Findings folds the two passes ("IPv6 addresses published", "IPv4 too"), and each row names the network. Take it further hands the first IPv6 address to the ASN Lookup and Reverse DNS, and `[address]:443` to the TCP Ping, the step that proves something answers there. Press "IPv6 only" and the page loads a sample name with no A records; "No IPv6" loads one with no AAAA records. ## For agents The Tamperbox MCP server exposes `aaaa_lookup` with a `name`, returning an `evidence` object with the question, status, flags, answer and authority, plus `records` for the requested type. It does not sort the addresses or look up their networks; use the `reverse_dns` operation, or an ASN lookup, for an address. Keep these warnings with any conclusion: - Record presence does not establish IPv6 reachability from the agent or the user. - Documentation and private ranges are never routed. - One answer from one resolver at one moment. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/). ## Limits - No connection is made to any address. - Network names come from routing registry data and name the announcing network, not the customer. - Pasted records get no network lookup and no A lookup. - One answer from one resolver at one moment. - Sample names under `.example` are answered in the browser. ## References - [RFC 3596](https://www.rfc-editor.org/rfc/rfc3596): DNS extensions to support IPv6. Sections 2.1, 2.3. - [RFC 4291](https://www.rfc-editor.org/rfc/rfc4291): IPv6 addressing architecture. Sections 2.5.2, 2.5.3, 2.5.5.2, 2.5.6, 2.7. Updated by [RFC 5952](https://www.rfc-editor.org/rfc/rfc5952) and others. - [RFC 4193](https://www.rfc-editor.org/rfc/rfc4193): unique local addresses. Section 3.1. - [RFC 3849](https://www.rfc-editor.org/rfc/rfc3849): IPv6 documentation prefix. Section 4. Updated by RFC 9637. - [RFC 9637](https://www.rfc-editor.org/rfc/rfc9637): expanding the documentation space, `3fff::/20`. Section 6. - [RFC 6052](https://www.rfc-editor.org/rfc/rfc6052): IPv6 addressing of IPv4/IPv6 translators. Section 2.1. - [RFC 8215](https://www.rfc-editor.org/rfc/rfc8215): local-use IPv4/IPv6 translation prefix. Section 1. - [RFC 3056](https://www.rfc-editor.org/rfc/rfc3056): 6to4. Section 2. - [RFC 4380](https://www.rfc-editor.org/rfc/rfc4380): Teredo. Section 2.6. - [RFC 8305](https://www.rfc-editor.org/rfc/rfc8305): Happy Eyeballs version 2. Sections 4, 5. Obsoletes [RFC 6555](https://www.rfc-editor.org/rfc/rfc6555). - [IANA IPv6 special-purpose address registry](https://www.iana.org/assignments/iana-ipv6-special-registry/). --- # Ads.txt & App-Ads.txt Checker How the ads.txt checker fetches and reads ads.txt and app-ads.txt, the rules it applies to every field, how it cross-checks sellers against each ad system's sellers.json, and how to fix each finding. Canonical: https://docs.tamperbox.dev/tools/ads-txt-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public host name that publishes ads.txt or app-ads.txt, or the file to paste Outputs: A verdict with skipped lines and sellers confirmed, a summary, each record against sellers.json, the file line by line with its variables, findings and repairs Limitations: At most 12 ad systems and 100 seller IDs each are looked up; a match is evidence, not proof of an active account; unreadable sellers.json files confirm nothing The tool page is [tamperbox.dev/ads-txt-checker](https://tamperbox.dev/ads-txt-checker). It checks `tamperbox.dev` live when opened, says how many lines buyers will skip and how many sellers sellers.json confirms, and lists every record. This page is the long version: where the file is fetched from, every rule, the sellers.json cross-check, what each finding means for the site's ad revenue, and how to fix it.
Where processing happens: a pasted file is read in your browser. Its sellers are looked up only when you press Look up sellers, which sends the ad system domains and seller IDs (not the file) to the Tamperbox server. A host name is sent to the server, which fetches the file and the ad systems' sellers.json files without cookies. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. Sample hosts on the reserved .example zone are answered in the browser from a fixture.
## What the tool answers 1. **Can buyers read the file?** It must be served as text at the root of the host, not as a web page. 2. **Which lines will buyers skip?** Any record missing a field, with a malformed domain, without a seller ID, or with a relationship other than DIRECT or RESELLER. 3. **Do the ad systems agree?** Each seller ID is looked up in its ad system's sellers.json: listed, of the type the line claims, and owned by this site for DIRECT lines. 4. **Is the file tidy?** Duplicates, conflicting relationships, unknown variables. ## Inputs ### A host `example.com` or a full address; the host is kept. The check runs when you stop typing, or on Enter. The **File** selector in the rail picks `ads.txt` (websites) or `app-ads.txt` (apps); changing it checks again. The usual refusals apply: spaces, other schemes, credentials, non-standard ports, IP addresses and single labels. ### A pasted file Text with a newline, a line starting `#`, a `NAME=value` variable, or a line with two commas (`greenadexchange.com, 1234, DIRECT`) is read as a file, in the browser. Sellers are not looked up until you press **Look up sellers**. Files up to 2 MiB can be dropped or opened. A pasted address loses quotes, brackets and trailing punctuation and keeps the host; text that fits nothing stays as pasted. ## Reading the result ### Verdict and chips "Valid ads.txt, n records for m ad systems, x of y sellers confirmed in sellers.json." or "n lines buyers will skip;" with the same counts. For a missing or HTML file, the verdict says so. Chips count skipped lines, sellers not matching and sellers confirmed, and scroll to the sellers table. Two items say where the input went. ### Findings Worst first, line findings prefixed with their line; two or more passing findings are grouped under an expandable **checks passed** row. A single passing finding stays visible. ### Summary Records, DIRECT and RESELLER counts, lines skipped by buyers and sellers confirmed, each with what it means. ### Sellers One row per record: its line, the ad system and seller ID, the relationship, and the sellers.json answer (the seller's name and type, confidential, not listed, or not looked up). ### File The file as written, numbered, with issue lines tinted, its variables above, and **Download** for the file as it stands (useful after a repair). Long files show their first 60 lines and every marked line; **Show all n lines** lists the rest, and **Show the first 60 lines** folds it again. Folding is offered only when at least ten unmarked lines after line 60 can be hidden; marked lines remain visible. ### History History follows the current result evidence. Break it and Heal it record input changes, newest first. **Revert** restores the input before the latest recorded change; **Reset input** restores the input before the first retained change and clears the list. **Restore input before this break** under Heal it also reverts the latest change. These actions reload and check the restored input. Restoring a public address can therefore send a new request, including on the two tools whose ordinary typing waits for a run button. Editing or pasting a new input clears History. The list lives in the current page; it is not saved monitoring data and does not restore an old network response. ### Take it further Only links with an available result value appear. | Follow-up | Value carried | When offered | | --- | --- | --- | | [Redirect Checker](https://tamperbox.dev/redirect-checker) | Checked host and selected `/ads.txt` or `/app-ads.txt` path | A host was checked | | [Website Down Checker](https://tamperbox.dev/website-down-checker) | First unavailable ad system's `/sellers.json` URL | A sellers.json lookup was unavailable | | [Email Domain Checker](https://tamperbox.dev/email-domain) | CONTACT value with a leading `mailto:` removed | The file's CONTACT value contains `@` | ### Related checks and input transfer Check the rest carries the current address to a sibling tool. Take it further carries the specific value listed above. Pasted file contents are not transferred through these links. Transfers temporarily use browser `sessionStorage` with a one-use random token in the URL fragment; the input itself is not in the URL. The destination accepts a transfer for less than one minute and removes the token. Manual destination tools wait for their run button or Enter. Each destination collects new evidence. A follow-up link does not confirm the original verdict or repair the remote site. ### Result cards Six expandable cards below the result explain its meaning, give a beginner explanation, offer an agent prompt, describe good practice, suggest fixes and state limitations. Their text follows the current result; it is not another measurement. Open a card for its full explanation and the relevant [Method](#method) or [Guide](#guide). The agent prompt can be copied for review; copying it does not run a repair or send it to an agent. ## Method ### Fetching the file The server requests `https:///ads.txt` (or `/app-ads.txt`) on the exact host entered: `www.example.com` and `example.com` are separate checks, as the [ads.txt 1.1 specification](https://iabtechlab.com/ads-txt/) ("Access method") places the file at the root of the domain. Plain HTTP is tried once only when the HTTPS attempt raises the `upstream_error` condition; other failures do not automatically trigger fallback. Up to 5 redirects are followed, with at most one crossing to another registrable domain; a second stops the fetch. The first 2 MiB is read. | Response | Severity | | --- | --- | | 400 or above | CHECK: no file, so buyers that check cannot confirm any seller | | HTML content type or body | FAIL: a catch-all route; no records | | A redirect to another host | INFO, per hop | | Text with no records | CHECK | ### Reading lines Following the specification's "File format" section: text after `#` is a comment; a line `NAME=value` with no comma is a variable; any other line is a record, `, , [, ]`, with extension data after `;`. | Rule | Severity | Repair | | --- | --- | --- | | Fewer than three fields | FAIL | | | Ad system not a bare domain (for example `https://exchange.com/`) | FAIL | Remove https:// from ad systems | | Ad system written with `www.` | CHECK | Drop www. from ad systems | | No seller account ID | FAIL | Remove lines without a seller ID | | Relationship not DIRECT or RESELLER | FAIL; names DIRECT or RESELLER when the value starts with "dir" or "res" | Write DIRECT and RESELLER correctly | | Relationship in lower case | INFO | Write DIRECT and RESELLER correctly | | Certification authority ID not 9 to 16 hexadecimal characters | INFO | | | More than four fields before `;` | CHECK | | | Unknown variable (known: CONTACT, SUBDOMAIN, INVENTORYPARTNERDOMAIN, OWNERDOMAIN, MANAGERDOMAIN) | CHECK | | | Same ad system and seller ID twice, same relationship | INFO | Remove duplicate lines | | Same ad system and seller ID as DIRECT and RESELLER | CHECK | | | Byte order mark | INFO | | A record with any FAIL counts as skipped by buyers: crawlers that read ads.txt drop records they cannot parse, so the account on such a line cannot sell. ### The sellers.json cross-check For a fetched file, the first 12 distinct ad systems are looked up, each once, asking for the first 100 unique seller IDs the file names for it. The server requests `https:///sellers.json` (Google's listing is at `realtimebidding.google.com`), follows up to 5 redirects, and stream-parses up to 32 MiB (128 MiB for Google). It must answer 200 with an object holding a `sellers` array, as the [sellers.json specification](https://iabtechlab.com/sellers-json/) defines; otherwise the system is "No readable sellers.json" (INFO) and its lines are neither confirmed nor rejected. | Answer for a record | Severity | | --- | --- | | Seller ID not listed | CHECK, "Not in sellers.json" | | DIRECT, but seller_type INTERMEDIARY; RESELLER, but seller_type PUBLISHER | CHECK | | DIRECT, listed seller domain differs from OWNERDOMAIN (or the host without www.) | INFO | | Listed with a fitting type, or confidential | PASS | | ID beyond the 100 checked | INFO, "Seller ID not checked" | DIRECT expects `PUBLISHER` or `BOTH`; RESELLER expects `INTERMEDIARY` or `BOTH`, matching the sellers.json `seller_type` values. ## Standards and conformance ### IAB Tech Lab ads.txt 1.1 Implemented: the access method at the root of the host with HTTPS first, the redirect allowance (one cross-domain hop), the record and variable formats and the variables listed above. app-ads.txt is read with the same rules, as the app-ads.txt extension of the specification defines. Not implemented: following `SUBDOMAIN` declarations to fetch subdomain files, and `INVENTORYPARTNERDOMAIN` chains for CTV. Stricter than the text: `www.` in an ad system is a CHECK because buyers compare exactly. ### IAB Tech Lab sellers.json 1.0 Implemented: the `sellers` array, `seller_id`, `seller_type`, `name`, `domain` and `is_confidential`. Not checked: the sellers.json file's own validity beyond what the cross-check needs, `identifiers`, and the supply chain object. Both are industry specifications published as documents by IAB Tech Lab, not RFCs; their pages above are the canonical sources. ## Finding reference ### File and record findings | Finding | Severity | What it means for ad revenue | Fix | | --- | --- | --- | --- | | No ads.txt (n) | CHECK | Buyers that require it do not bid | Publish the file | | ads.txt is a web page | FAIL | No sellers authorised | Serve text at the root | | Redirected from a to b | INFO | Allowed within one root domain | Keep redirects within your domain | | No records | CHECK | Nobody authorised | Add records | | Line n: Missing fields | FAIL | Line skipped | Three fields | | Line n: "x" is not a domain | FAIL | Line skipped | Bare domain (Heal it) | | Line n: Ad system written as www.x | CHECK | May not match | Drop www. (Heal it) | | Line n: No seller account ID | FAIL | Line skipped | Fill in or remove (Heal it) | | Line n: "x" is not DIRECT or RESELLER | FAIL | Line skipped | Correct it (Heal it) | | Line n: direct written in lower case | INFO | Most buyers accept | Capitals (Heal it) | | Line n: Certification ID "x" looks unusual | INFO | | Use the TAG ID | | Line n: Extra fields | CHECK | Extensions misread | Put them after `;` | | Line n: Unknown variable x | CHECK | Ignored | Use a defined variable | | Line n: Duplicate of line m | INFO | Harder to audit | Remove (Heal it) | | Line n: Listed as both DIRECT and RESELLER | CHECK | Buyers may distrust both | Keep the true one | ### Seller evidence | Finding | Severity | What it means for ad revenue | Fix | | --- | --- | --- | --- | | Line n: Not in sellers.json | CHECK | Cross-checking buyers skip it | Correct the ID or remove | | Line n: DIRECT but INTERMEDIARY, RESELLER but PUBLISHER | CHECK | Red flag for buyers | Fix the relationship or ID | | Line n: Seller domain is x | INFO | DIRECT account owned elsewhere | Confirm the account | | n seller IDs not checked | INFO | Over the lookup limit | Check them with the ad system | | No readable sellers.json for x | INFO | Cannot confirm | Nothing in your file | ## Guide ### Lines buyers skip 1. Filter the File section to the red lines. 2. Use the repairs in Heal it: each rewrites the whole file for review. 3. **Download** the corrected file and publish it at `/ads.txt`. Confirm outside Tamperbox: `curl -s https://example.com/ads.txt | head`. ### Sellers that do not match sellers.json 1. Open the row: it names what sellers.json says (the seller's name and type, or not listed). 2. Ask the ad system or your account manager for the exact line, and replace yours. 3. Check again with **Look up sellers** (pasted) or by re-entering the host. ### The file is missing or served as HTML Publish a plain text file at the exact path, before any catch-all route, on each host that serves ads. `curl -sI https://example.com/ads.txt` should show `200` and `text/plain`. ### Break it cases | Case | What it loads | What to look at | | --- | --- | --- | | Duplicate line | Your first record repeated | Duplicate finding; Heal it removes it | | Misspelled DIRECT | Your first DIRECT written DIRCT | Skipped line; Heal it corrects it | | Missing seller ID | Your first record without its ID | Skipped line; Heal it removes it | | Address, not a domain | Your first ad system written as a URL | Skipped line; Heal it strips it | | Served as a web page | A sample single-page app | HTML finding | | No ads.txt | A sample host without the file | No ads.txt | The first four are built from your own file when you entered a host or pasted one. ## Worked example The page opens by fetching `ads.txt` for `tamperbox.dev` and checking the eligible seller IDs from that current file. The counts and seller records are live evidence. Switch the file selector to inspect `app-ads.txt`; the selected file is fetched from the entered host. Read each row's parsing status before treating a seller match as meaningful. Compare the advertised account ID and relationship with the seller evidence. An unreadable sellers.json file is inconclusive, and an ID outside the configured lookup limits has not been verified. A matching record does not establish a commercial relationship or prove that a seller is authorized by your organization. For a controlled repair exercise, paste a copy of your file and choose a Break it case. Parsing stays local until you explicitly request seller lookups. Review the repaired text and its filename before publishing it through your normal workflow. After publication, fetch the correct root URL and rerun the live check to distinguish a local edit from the file buyers can actually retrieve. ## For agents Use the Tamperbox MCP `search` tool to inspect the schema, then `execute` with `tamperbox.request` to call `POST /v1/tools/ads_txt_checker`. Supply the required `domain` field as a public domain name. The operation is named `ads_txt_checker`; the browser page’s hyphenated identifier is not the API operation name. The operation fetches `ads.txt` and returns `evidence` and a parsed `report`. It does not select app-ads.txt or perform the browser’s sellers.json cross-check. Syntax findings and published seller records do not establish account ownership or contractual authorization. Keep the input, observation time, source limitations and inconclusive results with any summary. Browser fixtures are demonstrations, not live MCP targets. Do not turn missing evidence into a passing check or infer that an inaccessible resource has been deleted. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/), [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) and [Security and privacy](https://docs.tamperbox.dev/reference/security/). ## Limits - One fetch of the file (2 MiB) and at most 12 sellers.json files. - SUBDOMAIN and INVENTORYPARTNERDOMAIN declarations are listed, not followed. - Live checks are rate limited. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. ## References - [IAB Tech Lab ads.txt specification, version 1.1](https://iabtechlab.com/ads-txt/): access method, file format, variables, app-ads.txt. - [IAB Tech Lab sellers.json specification, version 1.0](https://iabtechlab.com/sellers-json/): the sellers object and seller_type. --- # ASN Lookup How the ASN Lookup finds the network that announces an address and the organisation its block is registered to, every rule behind its verdict and findings, and how to act on each one. Canonical: https://docs.tamperbox.dev/tools/asn-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public IPv4 or IPv6 address, an AS number from 1 to 4294967295, or a domain that resolves to an address Outputs: A verdict naming the origin network or networks, the routed prefix, the registered holder of the block, and findings that explain multiple origins, missing announcements and holder differences Limitations: Route collector data is a sample of the internet and lags real changes; the registry names the holder of a block, never the person using an address; a domain is checked through its first address only The tool page is [tamperbox.dev/asn-lookup](https://tamperbox.dev/asn-lookup). It opens on a live lookup of `tamperbox.dev`, answers in one sentence which network announces the address, and shows the evidence under it: the origin networks, the registration of the block and the findings. This page is the long version: what the lookup asks, every rule it applies, what each finding means for someone holding a log line or a firewall rule, and how to confirm the answer without Tamperbox.
Where processing happens: the input is read in your browser first. Private, loopback, link-local, shared (carrier-grade NAT) and unique local addresses are explained there and never sent. The documentation ranges that Break it uses are answered from sample data in the browser. Any other address or AS number is sent to the Tamperbox server, which asks RIPEstat and the address registry and returns the observation. A domain starts with an A query on the same server and falls back to AAAA only if no A address is returned; the first address in the selected answer is looked up.
## What the tool answers Three questions, in the order an operator asks them about an unfamiliar address: 1. **Is the address routed at all?** Does any network announce a prefix that covers it, as seen by the RIPE RIS route collectors? 2. **Which network announces it?** The origin autonomous system of that prefix, or several of them, with each network's name and whether it is announcing. 3. **Who holds the block?** The registration record from the regional internet registry: the registered name, handle, address range, country and contacts. For an AS number the questions shrink to two: who holds the number, and is it announcing anything. The verdict sentence answers the first open question; the chips repeat the origin and the registration so the two can be compared at a glance. ## Inputs ### A public IP address `1.1.1.1` or `2606:4700:4700::1111`. The lookup runs about 600 ms after typing pauses, or at once on Enter. The address is normalised (an IPv6 address is compressed) before it is sent. Only global unicast addresses are sent; the special-purpose ranges in [RFC 6890](https://www.rfc-editor.org/rfc/rfc6890#section-2.2.2) are explained instead: | Range | Explained as | Why it is not looked up | | --- | --- | --- | | `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` | Private address | [RFC 1918, section 3](https://www.rfc-editor.org/rfc/rfc1918#section-3): not routed on the internet | | `100.64.0.0/10` | Shared address used by carrier-grade NAT | [RFC 6598, section 4](https://www.rfc-editor.org/rfc/rfc6598#section-4) | | `127.0.0.0/8`, `::1` | Loopback address | Never leaves the machine | | `169.254.0.0/16`, `fe80::/10` | Link-local address | Never routed | | `fc00::/7` | Unique local address | [RFC 4193, section 3](https://www.rfc-editor.org/rfc/rfc4193#section-3) | | `192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`, `2001:db8::/32` | Documentation address | Answered from sample data ([RFC 5737, section 3](https://www.rfc-editor.org/rfc/rfc5737#section-3), [RFC 3849, section 2](https://www.rfc-editor.org/rfc/rfc3849#section-2)) | ### An AS number `AS13335` or `13335`, from 1 to 4294967295, the four-octet range of [RFC 6793](https://www.rfc-editor.org/rfc/rfc6793#section-3). AS 0 and numbers outside the range are refused with a message. The documentation numbers 64496 to 64511 and 65536 to 65551 ([RFC 5398, section 2](https://www.rfc-editor.org/rfc/rfc5398#section-2)) are answered from sample data. ### A domain `example.org` is resolved through our server's DNS endpoint: an A record first, and an AAAA record only when there is no A record. The first address returned is looked up, and the verdict says so ("example.org resolves to …"). A name behind a CDN or a load balancer therefore shows the provider that announces that one address, not necessarily the origin server, and the other addresses are not checked. ### Near misses and pasted text Pasting is forgiving. A full link keeps its host (`https://example.org/path` becomes `example.org`); quotes, brackets and trailing punctuation are dropped. Text that fits nothing stays exactly as pasted, and the tool's own message explains why. Some near misses get a one-click repair in Heal it instead of a lookup: - `AS 13335`, with a space, offers `AS13335`. - A URL typed by hand offers its host. - A prefix such as `198.51.100.24/24` offers the address, because this tool looks up one address; [BGP Route Lookup](https://docs.tamperbox.dev/tools/bgp-lookup/) takes prefixes. - An IPv4 address with a port (`192.0.2.1:443`) offers the address without it. A file dropped on the field or opened with Add a file is read in the browser; its first line becomes the input. ## Reading the result ### Verdict and chips One of three sentences for an address: "AS… announces [address] in [prefix]", "N networks announce [prefix]" (a warning), or "[address] is not announced" (a warning). For an AS number: "is announcing routes", "is not announcing any routes" (a warning) or "is not in use" (a warning). The chips name the origin (or the count of origins) and the registration; each one scrolls to its section. ### Findings Directly under the verdict, worst first. Every finding is listed in the [Finding reference](#finding-reference). The count on the right is the number of findings to check, never the informational ones. ### Announced by One row per origin network: the organisation name, its registry handle, the AS number and an Announcing or Not announcing badge. If the name lookup for an origin fails, the row says "Name unavailable right now" instead of dropping the network. The line on the right gives the source and the age of the routing data, for example "data from 4 hours ago". ### Registered to The registration of the address block: name, handle, address range, country and up to ten contacts with their roles (registrant, abuse, technical, administrative). The section is hidden for an AS number. ### History History records input changes made by Break it and Heal it. It appears after the complete result and before Take it further. Revert undoes the newest change; Reset input returns to the input before the first retained change. Restore input before this break is also available in Heal it when there is a change to undo. Restoring does not create another history entry. This history is held in the page and disappears on reload. Restoring valid input runs the lookup again; typing or pasting a different input starts a new history. ### Take it further These links carry values derived from the current result. A link is absent when its required evidence is missing; the tool does not invent a target. | Destination | Value and condition | | --- | --- | | [BGP Route Lookup](https://docs.tamperbox.dev/tools/bgp-lookup/) | The routed prefix, when present | | [Reverse DNS](https://docs.tamperbox.dev/tools/reverse-dns/) | The resolved address, only after a live domain lookup | | [TCP Ping](https://docs.tamperbox.dev/tools/tcp-ping/) | The live address on port 443, only when an origin was observed | Reserved sample results offer only the derived links supported by local sample data. A live destination applies its own input rules; measurement tools still wait for an explicit run. ### What this result means Six cards explain the current findings: Ask your agent, In plain words, What does it mean?, What good looks like, How to fix it, and Tool limitations. Expand a card to read the explanation and its method or guide link. Copying an agent prompt does not run another check. The cards interpret the evidence already shown; they are not an additional measurement or an independent confirmation. When the input is cleared, a check fails, or no result is available, result-specific cards clear and contextual links disappear. Read the verdict before relying on a card, and distinguish a missing observation from a confirmed negative result. ## Method ### 1. Reading the input The input is parsed in the browser by `parseAsnInput` in the order above: a spaced AS number, a URL, an AS number, a prefix, an IPv4 address with a port, an address, a dotted quad with an octet over 255, then a host name. The first rule that matches decides; anything else is refused as "not an IP address, AS number or domain". ### 2. Routed prefix and origin networks For an address, the server asks RIPEstat's `network-info` data call for the most specific prefix that RIPE RIS collectors see covering the address and the AS numbers originating it. The origin of a route is the AS that put it into BGP: the rightmost AS in the final `AS_SEQUENCE` of the route's `AS_PATH` ([RFC 4271, section 5.1.2](https://www.rfc-editor.org/rfc/rfc4271#section-5.1.2); the definition of "Route Origin ASN" in [RFC 6811, section 2](https://www.rfc-editor.org/rfc/rfc6811#section-2)). Duplicate origins are removed. An answer with more than 32 origins is refused as incomplete rather than shown partially. Names come from RIPEstat's `as-overview` for at most eight origins; beyond eight a finding lists every number. The verdict follows the number of origins. One origin is the expected state. Several origins are a warning because, in the words of [RFC 1930, section 7](https://www.rfc-editor.org/rfc/rfc1930#section-7), "Generally, a prefix can should belong to only one AS", and the exceptions (anycast, a customer announced by two providers, aggregation) are deliberate choices the tool cannot see. No observed origin produces a warning verdict. Collector absence does not prove that every network lacks a usable route. ### 3. Registration over RDAP In parallel, the server finds the registration through the Registration Data Access Protocol. It reads IANA's bootstrap file for IPv4 or IPv6 and picks the service by longest prefix match, as [RFC 9224, section 5](https://www.rfc-editor.org/rfc/rfc9224#section-5) specifies ("found by doing a longest match of the target address"). It uses only HTTPS base URLs, builds the `ip/
` query of [RFC 9082, section 3.1.1](https://www.rfc-editor.org/rfc/rfc9082#section-3.1.1), and follows at most three redirects, which covers address space transferred between registries. The answer must be an IP network object ([RFC 9083, section 5.4](https://www.rfc-editor.org/rfc/rfc9083#section-5.4)); the name, handle, start and end address, country and up to ten entities with their roles are kept. "No registration" appears only for a real RDAP not-found answer (an error document with `errorCode` 404, [RFC 9083, section 6](https://www.rfc-editor.org/rfc/rfc9083#section-6)). Any other failure, including a registry that rate-limits the request, reads "Registry unavailable", and the routing evidence stays on the page. ### 4. Comparing holder and announcer The page takes the first word of the registered name (split at a hyphen or a space) and looks for it in the name of the first origin network. If it is not there, an informational finding says the two differ. It is a plain text comparison: an organisation that uses unrelated names in the registry and in its AS record triggers it too, so read both names before drawing a conclusion. ### 5. AS numbers For an AS number the server asks RIPEstat's `as-overview` for the holder and whether the network announces any prefix. No RDAP query is made. A holder string such as `CLOUDFLARENET - Cloudflare, Inc.` is split so the organisation reads first and the handle is quieter. No holder and no announcement reads "is not in use"; a holder without an announcement reads "is not announcing any routes". ### Limits of the lookup itself | Limit | Value | | --- | --- | | Origins accepted from RIPEstat | 32 | | Origins named | 8 | | Registry contacts kept | 10 | | RDAP redirects followed | 3 | | Server time limit | 20 seconds | | Input length | 300 characters | ## Standards and conformance | Specification | Sections used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 4271](https://www.rfc-editor.org/rfc/rfc4271) BGP-4 | [5.1.2](https://www.rfc-editor.org/rfc/rfc4271#section-5.1.2) AS_PATH | The origin is read from collector data, not from a session of our own | No BGP session; no path, communities or local preference shown. Updated by RFC 6793 and later RFCs | | [RFC 6811](https://www.rfc-editor.org/rfc/rfc6811) origin validation | [2](https://www.rfc-editor.org/rfc/rfc6811#section-2) definitions | Origin AS as defined there | The tool does not compute Valid, Invalid or NotFound against RPKI; a second origin is flagged, not judged | | [RFC 1930](https://www.rfc-editor.org/rfc/rfc1930) BCP 6 | [7](https://www.rfc-editor.org/rfc/rfc1930#section-7) one prefix, one origin | More than one origin is a warning to check | It cannot tell intent; anycast and multi-homing are named as normal causes | | [RFC 6793](https://www.rfc-editor.org/rfc/rfc6793) four-octet ASNs | [3](https://www.rfc-editor.org/rfc/rfc6793#section-3) | Accepts 1 to 4294967295 | Does not flag private-use ([RFC 6996](https://www.rfc-editor.org/rfc/rfc6996#section-3)) numbers; the registry answer shows them as unheld | | [RFC 9224](https://www.rfc-editor.org/rfc/rfc9224) RDAP bootstrap | [5](https://www.rfc-editor.org/rfc/rfc9224#section-5) | Longest match in the IANA IPv4 or IPv6 file, HTTPS only | Obsoletes [RFC 7484](https://www.rfc-editor.org/rfc/rfc7484) | | [RFC 9082](https://www.rfc-editor.org/rfc/rfc9082) RDAP query | [3.1.1](https://www.rfc-editor.org/rfc/rfc9082#section-3.1.1) | `ip/
` | No AS-number RDAP query ([3.1.2](https://www.rfc-editor.org/rfc/rfc9082#section-3.1.2)); RIPEstat answers for AS numbers. Obsoletes [RFC 7482](https://www.rfc-editor.org/rfc/rfc7482) | | [RFC 9083](https://www.rfc-editor.org/rfc/rfc9083) RDAP response | [5.4](https://www.rfc-editor.org/rfc/rfc9083#section-5.4), [6](https://www.rfc-editor.org/rfc/rfc9083#section-6) | Reads the IP network object; only an error document with 404 means absent | Remarks, events and nested entities are not shown. Obsoletes [RFC 7483](https://www.rfc-editor.org/rfc/rfc7483) | | [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3), [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598#section-4), [RFC 4193](https://www.rfc-editor.org/rfc/rfc4193#section-3), [RFC 6890](https://www.rfc-editor.org/rfc/rfc6890#section-2.2.2) | as listed | Special-purpose ranges are explained in the browser and never sent | | | [RFC 5737](https://www.rfc-editor.org/rfc/rfc5737#section-3), [RFC 3849](https://www.rfc-editor.org/rfc/rfc3849#section-2), [RFC 5398](https://www.rfc-editor.org/rfc/rfc5398#section-2) | as listed | Documentation addresses and numbers are answered from labelled sample data | | ## Finding reference | Finding | Severity | What it means for whoever holds the address | Fix | | --- | --- | --- | --- | | No network announces this address | CHECK | The selected collectors report no covering route; other observations may differ | The holder announces the covering prefix, with a route object and an RPKI ROA | | N origin networks for one prefix | CHECK | Several networks originate the prefix: anycast or multi-homing on purpose, or a misconfiguration or hijack | Compare origins in BGP Route Lookup; ask the holder which it authorised | | No routes seen from this network | CHECK | The AS is registered but announces nothing collectors see | Its operator checks sessions and exports | | No holder and no routes | CHECK | No holder or announcement was reported; this does not independently establish allocation status | Check for a typo; investigate where it appeared | | Registered holder and announcing network differ | INFO | Another network routes the block: a provider for a customer, leased space, mitigation | Report abuse to the announcing network first | | Names shown for the first eight networks | INFO | More than eight origins; all numbers are listed | Look the remaining numbers up one by one | | No registration record | INFO | The registry has no record: unallocated or reserved space | | | The registry did not answer | INFO | The holder is unknown for now; routing evidence is unaffected | Check again later | | This names a network, not a person | INFO | Both names are organisations; neither is a customer or a location | | | Its prefixes and visibility | INFO | BGP Route Lookup holds the per-prefix evidence for an AS | | ## Guide ### You found an address in a log or a firewall alert 1. Enter the address. Read the verdict: the origin network is the organisation operating the address. 2. Open Registered to and find the contact with the role `abuse`. If the announcing network differs from the holder, write to the announcing network's abuse contact first; it runs the machines. 3. Include the address, timestamps with their time zone, and the log lines. Never include more of your own data than the report needs. Confirm the origin without Tamperbox with the RIPEstat data call the server uses: ```sh curl -s 'https://stat.ripe.net/data/network-info/data.json?resource=1.1.1.1' ``` and the registration with the RDAP service of the registry (or any RDAP client): ```sh curl -s https://rdap.apnic.net/ip/1.1.1.1 whois -h whois.radb.net -- '-i origin AS13335' ``` ### The address has two or more origins Open [BGP Route Lookup](https://docs.tamperbox.dev/tools/bgp-lookup/) for the prefix by entering the prefix there. Compare each origin's route object, first-seen date and visibility. An origin with no route object and a recent first-seen date is the one to ask about. If you hold the prefix, publish an RPKI ROA naming the origins you authorise, so validating networks can evaluate origin authorization; filtering remains their own policy. ### The address is not announced If it should be reachable, the holder announces the covering prefix from its border routers and registers a route object and a ROA. If it should not be reachable (a withdrawn block, internal space), the result is the expected one. ### A domain points at a CDN The first address of a CDN-hosted name belongs to the CDN. To find the origin server you need its own address, which the CDN hides by design; this tool cannot reveal it. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | Two origin networks | `203.0.113.10` | A sample prefix originated by two networks, with the MOAS warning | | Not announced | `192.0.2.1` | A sample address no network announces | | A network with no routes | `AS64510` | A documentation AS that is registered but announces nothing, with the "No routes seen from this network" warning | | A prefix, not an address | your address with `/24` (or `/48`) | The refusal and the Heal it repair back to the address | | Private address | `10.20.4.17` | The private-range explanation; nothing is sent | | Not an address | your IPv4 address with the last octet set to 300 | The octet range error | ## Worked example The page resolves `tamperbox.dev` live and looks up the first address returned. Read the resolved address before interpreting the route: a CDN or multi-address hostname can select different endpoints over time. Compare the observed prefix and origins with the registration panel. A holder/announcer difference is a string-based prompt to investigate, not evidence of abuse or an unauthorized route. For an independent comparison, enter the selected address directly, then check the prefix in BGP Route Lookup. Record the observation time and source alongside the result. Neither the current origin count nor the registered holder of this live default is fixed by this guide. ## For agents The Tamperbox MCP server runs the same lookup. Search its catalog for the `asn_lookup` operation, inspect the input schema, and call it with one public address or AS number (resolve a domain first). Keep these warnings with any conclusion: - The origin and the registration are organisations; neither identifies a person or a location. - Collector data lags by hours and covers the collectors' peers, not every network. - Several origins are not a hijack by themselves; neither is a single origin proof that the announcement is authorised. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the input travels. ### Transfers to another tool Explicit sibling-tool controls can carry the current input or observed address to another page. The shared navigation stores that value temporarily in tab-scoped `sessionStorage`, accepts a transfer for at most one minute, and puts a random transfer token in the URL fragment. The input itself is not placed in the URL. The receiving page consumes the transfer and applies its own input rules; tools with a manual Run button still require that action for live checks. This is not a saved result, and the destination can send the value to the services it needs. Ordinary edits and lookups do not create a durable report archive. ## Limits - One lookup from the RIPE RIS view of the internet at one moment; routes that only some networks see may be missing. - The tool does not validate origins against RPKI and does not show AS paths. - A domain is checked through its first address only. - The registry country describes the record, not where the address is used. - Sample answers for documentation ranges are made up and labelled as sample data. - The page keeps results in memory. Explicit transfers to another tool use temporary session storage. ## References - [RFC 4271](https://www.rfc-editor.org/rfc/rfc4271), A Border Gateway Protocol 4: section 5.1.2. Updated by RFC 6793 and later RFCs. - [RFC 6811](https://www.rfc-editor.org/rfc/rfc6811), BGP Prefix Origin Validation: section 2. - [RFC 1930](https://www.rfc-editor.org/rfc/rfc1930), Guidelines for creation, selection, and registration of an Autonomous System (BCP 6): section 7. - [RFC 6793](https://www.rfc-editor.org/rfc/rfc6793), BGP Support for Four-Octet AS Number Space: section 3. Obsoletes [RFC 4893](https://www.rfc-editor.org/rfc/rfc4893). - [RFC 6996](https://www.rfc-editor.org/rfc/rfc6996), Autonomous System Reservation for Private Use: section 3. - [RFC 9224](https://www.rfc-editor.org/rfc/rfc9224), Finding the Authoritative RDAP Service: section 5. Obsoletes [RFC 7484](https://www.rfc-editor.org/rfc/rfc7484). - [RFC 9082](https://www.rfc-editor.org/rfc/rfc9082), RDAP Query Format: sections 3.1.1 and 3.1.2. Obsoletes [RFC 7482](https://www.rfc-editor.org/rfc/rfc7482). - [RFC 9083](https://www.rfc-editor.org/rfc/rfc9083), JSON Responses for RDAP: sections 5.4 and 6. Obsoletes [RFC 7483](https://www.rfc-editor.org/rfc/rfc7483). - [RFC 6890](https://www.rfc-editor.org/rfc/rfc6890), Special-Purpose IP Address Registries: section 2.2.2. - [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3), [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598#section-4), [RFC 4193](https://www.rfc-editor.org/rfc/rfc4193#section-3): private, shared and unique local address space. - [RFC 5737](https://www.rfc-editor.org/rfc/rfc5737#section-3), [RFC 3849](https://www.rfc-editor.org/rfc/rfc3849#section-2), [RFC 5398](https://www.rfc-editor.org/rfc/rfc5398#section-2): documentation addresses and AS numbers. - [IANA Autonomous System Numbers registry](https://www.iana.org/assignments/as-numbers/as-numbers.xhtml) and [IANA RDAP bootstrap files](https://data.iana.org/rdap/). - [RIPEstat Data API](https://stat.ripe.net/docs/data-api/ripestat-data-api), the source of the routing data. --- # BGP Route Lookup How the BGP Route Lookup reads who originates a prefix, how widely route collectors see it, its route objects and related prefixes, and the reported hijack and leak feed, with every rule and how to act on each finding. Canonical: https://docs.tamperbox.dev/tools/bgp-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: An IPv4 or IPv6 prefix, a public IP address, an AS number, or a domain that resolves to an address Outputs: A verdict naming the origin network and the share of collector peers that see the prefix, findings on multiple origins, missing route objects, low visibility and withdrawn routes, and a live incident feed Limitations: Collector data is a sample of the internet and lags by hours; RPKI validity is not computed; reported incidents are detections, not confirmed attacks The tool page is [tamperbox.dev/bgp-lookup](https://tamperbox.dev/bgp-lookup). It opens on a live lookup of `tamperbox.dev`, says in one sentence who announces the prefix and how widely it is seen, and shows the evidence under it: visibility, first and last seen, origin networks with their route objects, related prefixes, and a live feed of reported hijacks and route leaks. This page is the long version: what the lookup reads, the rules behind each finding, and how to act on them.
Where processing happens: the input is parsed in your browser. Private space is explained there and never sent, and the documentation ranges that Break it uses are answered from sample data in the browser. Any other prefix, address or AS number is sent to the Tamperbox server, which asks RIPEstat and returns the observation; a domain costs one DNS lookup first. The incident feed is fetched by the server from Cloudflare Radar and does not include your input unless you filter it to one network.
## What the tool answers 1. **Is the prefix announced?** Does any network originate it now, as seen by the RIPE RIS route collectors? 2. **Who originates it?** One network, or several, and does each have a route object in an Internet Routing Registry? 3. **How widely is it seen?** How many of the collectors' peers carry a route for it, and since when? 4. **What is around it?** More specific prefixes that take traffic from parts of it, less specific prefixes that cover it, and the registry block it was allocated from. 5. **Has anything been reported?** Potential hijacks and route leaks in the last 1, 7 or 30 days, optionally narrowed to the network you looked up. ## Inputs ### A prefix `8.8.8.0/24` or `2001:4860::/32`. The lookup runs about 600 ms after typing pauses, or at once on Enter. A prefix with host bits set (`8.8.8.8/24`) is read as its network address, because routing tables hold the network address, and the page says so in a finding with a Heal it repair to the exact form. A prefix longer than the address allows (`/33` for IPv4, `/129` for IPv6) is refused with a repair to the longest valid length. ### An address `8.8.8.8` is looked up through the prefix that contains it: RIPEstat answers with the most specific covering route. The verdict says "8.8.8.8 is in 8.8.8.0/24". ### An AS number `AS15169` or `15169`, from 1 to 4294967295 ([RFC 6793, section 3](https://www.rfc-editor.org/rfc/rfc6793#section-3)). The result is the network's holder, whether it announces anything, and the number block it was assigned from. Very large networks can take many seconds to answer; the server stops after 20 seconds. ### A domain `example.org` is resolved through our server's DNS endpoint (A first, AAAA when there is no A), and the first address is looked up. A name behind a CDN shows the CDN's prefix. ### Pasted text and near misses A pasted link keeps its host; quotes, brackets and trailing punctuation are dropped; text that fits nothing stays as pasted with the tool's own message. `AS 15169` with a space and a typed URL get a Heal it repair. Private space ([RFC 1918, section 3](https://www.rfc-editor.org/rfc/rfc1918#section-3)), loopback, link-local, shared CGN space ([RFC 6598, section 4](https://www.rfc-editor.org/rfc/rfc6598#section-4)) and unique local addresses ([RFC 4193, section 3](https://www.rfc-editor.org/rfc/rfc4193#section-3)) are refused in the browser: they are not routed on the internet. A file dropped on the field is read in the browser; its first line becomes the input. ## Reading the result ### Verdict and chips "[prefix] is announced by AS…" (a pass when at least half the collector peers see it), "is announced by N networks" (a warning), or "is not announced" (a warning). The detail line gives visibility: "Seen by 325 of 325 route collector peers (100%)". Chips repeat the origin, the visibility and, when the second call failed, "Routing status unavailable". ### Findings Directly under the verdict, worst first. Each finding is in the [Finding reference](#finding-reference). ### Visibility The count of collector peers that see the prefix over its address family, a bar of seeing against missing peers, and a timeline with First seen and Last seen, each with the origin at that time. The source line gives the age of the data. ### Origin networks One row per origin with its name, handle and a badge: "Route object in RADB" (or the databases listed), or "No route object". ### Related prefixes More specific prefixes also announced, less specific prefixes that cover this one, and the registry block (for example "8.0.0.0/8, Administered by ARIN"). For an AS number: the number block, who assigned it and the registry. ### Reported hijacks and leaks The live feed from Cloudflare Radar, newest first, 25 to a page and up to 20 pages. Switch between Hijacks and Route leaks and between the last 24 hours, 7 days and 30 days. After an AS lookup or a prefix with exactly one origin, a chip narrows the feed to that network. Hijack rows show the detection time, prefixes, the announcing network, the expected origin and a confidence: High for a provider score of 8 or more, Medium for 5 to 7, Low below. Leak rows show the leaking network, the path segment, the number of prefixes and peers, and whether the leak has ended. ### History History records input changes made by Break it and Heal it. It appears after the complete result and before Take it further. Revert undoes the newest change; Reset input returns to the input before the first retained change. Restore input before this break is also available in Heal it when there is a change to undo. Restoring does not create another history entry. This history is held in the page and disappears on reload. Restoring valid input runs the lookup again; typing or pasting a different input starts a new history. ### Take it further These links carry values derived from the current result. A link is absent when its required evidence is missing; the tool does not invent a target. | Destination | Value and condition | | --- | --- | | [ASN Lookup](https://docs.tamperbox.dev/tools/asn-lookup/) | The first origin AS, when a prefix has an origin | | [BGP Route Lookup](https://docs.tamperbox.dev/tools/bgp-lookup/) | The first less-specific covering prefix, for live results | | [WHOIS/RDAP Lookup](https://docs.tamperbox.dev/tools/whois-lookup/) | The network address of the live prefix | Reserved sample results offer only the derived links supported by local sample data. A live destination applies its own input rules; measurement tools still wait for an explicit run. ### What this result means Six cards explain the current findings: Ask your agent, In plain words, What does it mean?, What good looks like, How to fix it, and Tool limitations. Expand a card to read the explanation and its method or guide link. Copying an agent prompt does not run another check. The cards interpret the evidence already shown; they are not an additional measurement or an independent confirmation. When the input is cleared, a check fails, or no result is available, result-specific cards clear and contextual links disappear. Read the verdict before relying on a card, and distinguish a missing observation from a confirmed negative result. ## Method ### 1. Reading the input `parseBgpInput` in the browser tries, in order: a spaced AS number, a URL, an AS number, a prefix (refusing a length over /32 or /128, refusing private space, normalising host bits), an address, a dotted quad with an octet over 255, and a host name. The server repeats the checks: it accepts only public addresses and normalises the prefix to its network address before asking RIPEstat. ### 2. Overview and routing status The server makes two RIPEstat calls in parallel: `prefix-overview` (or `as-overview` for an AS number) and `routing-status`. The overview gives whether the prefix is announced, the origin networks with their holders, related prefixes and the registry block. The routing status gives visibility per address family, first and last seen with the origin at those times, the route objects per origin, and the more and less specific prefixes. If the routing status fails, the result is marked partial: the overview stands and the page says the rest is unavailable. The origin of a route is the AS that introduced it into BGP, the rightmost AS in the final `AS_SEQUENCE` of the route's `AS_PATH` ([RFC 4271, section 5.1.2](https://www.rfc-editor.org/rfc/rfc4271#section-5.1.2); "Route Origin ASN" in [RFC 6811, section 2](https://www.rfc-editor.org/rfc/rfc6811#section-2)). The collectors record the origins their peers see; the tool reports them as RIPEstat lists them. ### 3. Rules applied to a prefix | Rule | Condition | Finding | | --- | --- | --- | | Host bits | The typed prefix had host bits set | INFO, with a Heal it repair to the network address | | Multiple origins | More than one origin network | CHECK | | Route objects | An origin has an empty route object list | CHECK, naming the origins without one | | Visibility | Announced and seen by fewer than 50% of collector peers | CHECK | | More specifics | Any more specific prefix announced | INFO | | Not announced | No announcement now | CHECK, with the last-seen time when known | | Partial | The routing status call failed | INFO | | Collector sample | Always | INFO | The multiple-origin warning follows [RFC 1930, section 7](https://www.rfc-editor.org/rfc/rfc1930#section-7): "Generally, a prefix can should belong to only one AS", with exceptions that only the holder can confirm, such as anycast or a customer announced by two providers. The route object rule reflects common practice: many networks build their prefix filters from IRR data, as [RFC 7454, section 6.1](https://www.rfc-editor.org/rfc/rfc7454#section-6.1) describes. The visibility threshold is a heuristic, not a standard: a prefix seen by fewer than half the collector peers merits investigation; the percentage alone does not identify filtering or its cause. A frequent reason is length: [RFC 7454, section 6.1.3](https://www.rfc-editor.org/rfc/rfc7454#section-6.1.3) records that "IPv4 prefixes longer than /24 and IPv6 prefixes longer than /48 are generally neither announced nor accepted". ### 4. Rules applied to an AS number An AS that announces nothing is a warning ("No routes seen from this network"). An informational finding points at the incident feed, which can be narrowed to the network. ### 5. The incident feed The server reads Cloudflare Radar's BGP hijack or route leak events for the chosen period, sorted newest first, 25 per page. For hijacks, the filter matches any involved network; for leaks, it matches the leaking network, following the provider's own semantics. A route leak is defined in [RFC 7908, section 2](https://www.rfc-editor.org/rfc/rfc7908#section-2) as "the propagation of routing announcement(s) beyond their intended scope". The feed needs a configured provider token; without one the page says the feed is not connected and the routing results are unaffected. The feed is never sampled: sample incidents would read as real ones. ## Standards and conformance | Specification | Sections used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 4271](https://www.rfc-editor.org/rfc/rfc4271) BGP-4 | [5.1.2](https://www.rfc-editor.org/rfc/rfc4271#section-5.1.2) | Origins are read from collector observations | No session of our own, no AS paths or attributes shown. Updated by RFC 6793 among others | | [RFC 6811](https://www.rfc-editor.org/rfc/rfc6811) origin validation | [2](https://www.rfc-editor.org/rfc/rfc6811#section-2) | Origin defined as there | Valid, Invalid and NotFound are not computed; ROAs are not fetched | | [RFC 6480](https://www.rfc-editor.org/rfc/rfc6480) RPKI | [3](https://www.rfc-editor.org/rfc/rfc6480#section-3) ROAs | Recommended in the guide as the way to authorise origins | Not checked by the tool | | [RFC 1930](https://www.rfc-editor.org/rfc/rfc1930) BCP 6 | [7](https://www.rfc-editor.org/rfc/rfc1930#section-7) | More than one origin is a warning | Intent cannot be seen in routing data | | [RFC 7454](https://www.rfc-editor.org/rfc/rfc7454) BGP operations | [6.1](https://www.rfc-editor.org/rfc/rfc7454#section-6.1), [6.1.3](https://www.rfc-editor.org/rfc/rfc7454#section-6.1.3) | Explains missing route objects and low visibility | The tool does not test any network's filters | | [RFC 7908](https://www.rfc-editor.org/rfc/rfc7908) route leaks | [2](https://www.rfc-editor.org/rfc/rfc7908#section-2), [3](https://www.rfc-editor.org/rfc/rfc7908#section-3) | Leak events are labelled as the provider classifies them | Not independently verified | | [RFC 6793](https://www.rfc-editor.org/rfc/rfc6793) | [3](https://www.rfc-editor.org/rfc/rfc6793#section-3) | Four-octet AS numbers accepted | | | [RFC 5737](https://www.rfc-editor.org/rfc/rfc5737#section-3), [RFC 3849](https://www.rfc-editor.org/rfc/rfc3849#section-2), [RFC 5398](https://www.rfc-editor.org/rfc/rfc5398#section-2) | as listed | Documentation prefixes and numbers answer from labelled sample data | | ## Finding reference | Finding | Severity | What it means for the prefix's users | Fix | | --- | --- | --- | --- | | N origin networks | CHECK | BGP policy selects among routes; geographic distance is not decisive; a wrong origin captures real traffic | Confirm the authorised origins; publish a ROA naming them | | No route object for AS… | CHECK | Networks filtering on IRR data may drop the route | Register a route object for the prefix and origin | | Only N% of collector peers see it | CHECK | Users behind networks that filter or never hear it cannot reach it | Check prefix length, ROA maximum length and upstream exports | | Not announced now | CHECK | The collectors do not currently report the announcement; a covering route may still carry traffic | Announce it again, with route object and ROA in place | | No routes seen from this network | CHECK | The AS announces nothing collectors see | Its operator checks sessions and exports | | … has host bits set | INFO | The typed prefix was read as its network address | Use the network address (Heal it) | | N more specific prefixes | INFO | Traffic to those parts follows the more specific route | Make sure each is intended and has its own ROA | | Routing status did not answer | INFO | The overview returned, but visibility, first/last seen and route-object details are unavailable | Retry later; do not treat missing details as a negative finding | | Collectors are a sample of the internet | INFO | Observations lag and cover only the collectors' peers | | | Incidents involving this network | INFO | The feed below can be narrowed to the network | | ## Guide ### Users cannot reach your new prefix 1. Look up the prefix. If it is "not announced", the announcement has not left your routers: check the BGP session and export policy with each upstream provider. 2. If it is announced but visibility is low, check its length (no longer than /24 for IPv4 or /48 for IPv6) and your ROA: a ROA whose maximum length is shorter than the announced prefix makes the announcement RPKI-invalid, and validating networks drop it. 3. If an origin has no route object, register one in your registry's IRR database, then check again after the mirrors update. Confirm without Tamperbox with the same RIPEstat data calls the server uses: ```sh curl -s 'https://stat.ripe.net/data/routing-status/data.json?resource=8.8.8.0/24' curl -s 'https://stat.ripe.net/data/prefix-overview/data.json?resource=8.8.8.0/24' whois -h whois.radb.net 8.8.8.0/24 ``` ### A second origin appears for your prefix Compare the two rows: the new origin's first-seen date, its route object, and whether the feed reports a hijack involving your network. If you did not authorise it, contact that network's NOC and your upstream providers with the evidence, and publish a ROA for your authorised origin so that validating networks reject the other. ### You run an AS and want to watch for incidents Look up your AS number and turn on the filter chip in the feed. Detections are probabilistic: a High confidence row deserves a look, a Low one usually does not. An empty feed is not proof that nothing happened. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | Two origin networks | `203.0.113.0/24` | A sample prefix with two origins, one without a route object | | Not announced | `192.0.2.0/24` | A sample prefix nobody announces | | Host bits set | your IPv4 prefix with `.24` in place of `.0` | The host-bits finding and the Heal it repair | | Prefix too long | your prefix with `/33` (or `/129`) | The length refusal and the repair to the longest valid length | | Private space | `10.0.0.0/8` | The refusal in the browser; nothing is sent | ## Worked example The page opens by resolving `tamperbox.dev` and looking up routing evidence for the selected address. Read the prefix returned by the overview, its origin networks and the data timestamp. The values can change with hosting, DNS or routing changes. If detailed routing status is available, compare the peer counts, first-seen information, route objects and related prefixes. The visibility percentage describes the participating collectors, not the percentage of internet users who can connect. A missing exact announcement can coexist with a usable less-specific route. The incident feed is a separate request. An unavailable or unconfigured feed does not invalidate the routing overview, and an empty incident page is not a clean bill of health. Record those two evidence states separately. ## For agents The Tamperbox MCP server runs the same lookup. Search its catalog for `bgp_lookup`, inspect the input schema, and call it with one prefix, public address or AS number. `bgp_lookup` returns the overview and optional routing detail, with `status: partial` when detail is unavailable. The incident feed is the separate `bgp_events` operation; an unconfigured feed returns `feed_unavailable`. Keep these warnings with any conclusion: - Multiple origins are not a hijack by themselves, and one origin is not proof the announcement is authorised. - Visibility is measured at the collectors' peers, not at every network. - RPKI validity is not part of the result. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/), and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the input travels. [ASN Lookup](https://docs.tamperbox.dev/tools/asn-lookup/) answers the registration side of the same question. ### Transfers to another tool Explicit sibling-tool controls can carry the current input or observed address to another page. The shared navigation stores that value temporarily in tab-scoped `sessionStorage`, accepts a transfer for at most one minute, and puts a random transfer token in the URL fragment. The input itself is not placed in the URL. The receiving page consumes the transfer and applies its own input rules; tools with a manual Run button still require that action for live checks. This is not a saved result, and the destination can send the value to the services it needs. Ordinary edits and lookups do not create a durable report archive. ## Limits - One view, RIPE RIS, at one moment; routes seen only inside some networks are missing. - No AS paths, no RPKI validation, no route object contents beyond the database names. - An address is looked up through its most specific covering prefix; a domain through its first address. - The incident feed is a third-party detection service; it needs a configured token and may be unavailable. - Sample answers for documentation ranges are made up and labelled. - The page keeps results in memory. Explicit transfers to another tool use temporary session storage. ## References - [RFC 4271](https://www.rfc-editor.org/rfc/rfc4271), A Border Gateway Protocol 4: section 5.1.2. Updated by RFC 6793 and later RFCs. - [RFC 6811](https://www.rfc-editor.org/rfc/rfc6811), BGP Prefix Origin Validation: section 2. - [RFC 6480](https://www.rfc-editor.org/rfc/rfc6480), An Infrastructure to Support Secure Internet Routing: section 3. - [RFC 1930](https://www.rfc-editor.org/rfc/rfc1930), Guidelines for creation, selection, and registration of an Autonomous System (BCP 6): section 7. - [RFC 7454](https://www.rfc-editor.org/rfc/rfc7454), BGP Operations and Security (BCP 194): sections 6.1 and 6.1.3. - [RFC 7908](https://www.rfc-editor.org/rfc/rfc7908), Problem Definition and Classification of BGP Route Leaks: sections 2 and 3. - [RFC 6793](https://www.rfc-editor.org/rfc/rfc6793), BGP Support for Four-Octet AS Number Space: section 3. - [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3), [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598#section-4), [RFC 4193](https://www.rfc-editor.org/rfc/rfc4193#section-3): private, shared and unique local address space. - [RFC 5737](https://www.rfc-editor.org/rfc/rfc5737#section-3), [RFC 3849](https://www.rfc-editor.org/rfc/rfc3849#section-2), [RFC 5398](https://www.rfc-editor.org/rfc/rfc5398#section-2): documentation addresses and AS numbers. - [RIPEstat Data API](https://stat.ripe.net/docs/data-api/ripestat-data-api) and [Cloudflare Radar routing](https://radar.cloudflare.com/routing), the data sources. --- # BIMI Record Checker How the checker reads a BIMI record, fetches and inspects the logo and the mark certificate, checks the DMARC policy BIMI depends on, every rule it applies, what each finding means for logo display, and how to fix each one. Canonical: https://docs.tamperbox.dev/tools/bimi-checker/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain, or a BIMI record, an SVG logo or a PEM certificate to paste Outputs: A verdict with PASS, CHECK and FAIL chips, the logo previewed on light and dark inboxes, the readiness steps, the SVG checks, the certificate as rows, and the findings with their fixes Limitations: Full SVG conformance, certificate trust, revocation and logo hash matching are not verified; only the default selector is looked up; each mailbox provider decides whether to show a logo The tool page is [tamperbox.dev/bimi-checker](https://tamperbox.dev/bimi-checker). It opens on a live check of `tamperbox.dev`; replace that domain to inspect your own. This page is the long version: what is fetched and how, every rule applied to the record, the logo, the certificate and the DMARC policy, what each finding means, and how to fix each one.
Where processing happens: a domain is sent to the Tamperbox server, which asks public DNS for the default._bimi and _dmarc records and fetches the logo and the certificate the record names. A pasted record, SVG or PEM is read in your browser; the logo is drawn as an image, so nothing in it runs. Nothing is stored.
## What the tool answers BIMI lets a domain publish a logo that supporting mailbox providers show next to its messages, on top of DMARC enforcement. The tool answers: 1. **Is there a record, and does it point at a logo?** The `default._bimi` TXT record with its `l=` and `a=` tags. 2. **Does the logo meet the profile?** The SVG as text against the Tiny Portable/Secure rules, with a preview on light and dark inboxes. 3. **Is there a usable mark certificate?** The PEM's logotype extension, validity window and the domains it names. 4. **Does DMARC enforce?** Quarantine or reject at 100%, without `sp=none`. It does not verify certificate trust, revocation or the hash of the embedded logo, and no provider's display decision is predicted. BIMI is not an RFC. The checker follows the individual Internet-Draft draft-brand-indicators-for-message-identification-14, its companion drafts for the logo profile and the mark certificate, the BIMI Group's published guidance where the code applies it, and RFC 9989 for DMARC. [Standards and conformance](#standards-and-conformance) lists what is implemented and where the tool differs. ## Inputs ### A domain `example.com`. When you stop typing, or on Enter, the server reads the two DNS records, then fetches the logo and the certificate named in the record. When both lookups fail because the lookup service is unavailable, the page reports an error. ### A BIMI record Paste `v=BIMI1; l=https://…; a=https://…`. Its syntax is checked in the browser; the logo, certificate and DMARC policy are not fetched for a pasted record. ### An SVG logo Paste the SVG text or drop the `.svg` file. It is checked as text against the profile and previewed as an image. Heal it offers the attribute repairs. ### A PEM certificate Paste the PEM text or drop the `.pem` or `.crt` file. The first certificate in it is decoded. A pasted certificate is not compared with any domain. ## Reading the result ### Verdict and chips For a domain, the verdict names the blocker: the DMARC policy when it is the only failure, otherwise the first failure, or "BIMI inspected" when every part passes. For a pasted logo or certificate it says whether the basic checks passed. The chips show the SVG result, the certificate, the DMARC state and the number of findings; each is a button that scrolls to the section that explains it. ### Findings Everything found, worst first; passes fold into one line. A DMARC finding carries an "Open the DMARC checker" button that hands the domain over. The [finding reference](#finding-reference) lists them all. ### Take it further Links that carry a derived value into another tool: the TLS certificate of the host that serves the logo, the mark certificate's expiry as a Unix timestamp, and DNSSEC on the zone. Each opens the destination with the value already in its box; nothing is put in the URL. ### History and Heal it History logs every Break it and Heal it change with what it replaced; Revert undoes the newest, Reset input returns to what you entered. Heal it offers repairs for a pasted SVG: pad the viewBox to a square without stretching the artwork, set the Tiny PS profile attributes, add a title, remove scripts and event handlers. ### Logo preview The logo drawn as an image on a light and a dark inbox, as a large avatar and in two message rows, so nothing in the SVG runs. The note says whether it is square. ### Basic readiness The four parts in order, each with its status: the record, the logo, the certificate, DMARC. ### SVG Tiny PS profile Every profile check with its status and the file's size. ### Mark certificate The certificate as rows: subject, valid until, logotype extension, the domains it names, and how many certificates the file holds. ## Method Each rule below names the document it comes from. BIMI sections refer to [draft-brand-indicators-for-message-identification-14](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html) ("BIMI draft"), logo sections to [draft-svg-tiny-ps-abrotman-12](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html) ("SVG Tiny PS draft") and certificate sections to [draft-fetch-validation-vmc-wchuang-11](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html) ("VMC draft"). A rule marked "Tamperbox" is this checker's own choice, not a requirement of any specification. ### Finding the record The server reads TXT records at `default._bimi.`, the name the [BIMI draft §7.2](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.2) step 2 builds when a message names no selector: "Otherwise the value 'default' MUST be used for the selector." Other selectors, local-part selectors ([§4.5](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.5)) and the fallback to the organizational domain (§7.2 step 6) are not looked up. A record published as several strings is joined without spaces, as [§4](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4) requires by pointing at [RFC 7208 §3.3](https://www.rfc-editor.org/rfc/rfc7208#section-3.3). Only records whose joined text starts exactly with `v=BIMI1`, followed by `;` or the end of the record, are kept, and exactly one must remain. §7.2 step 9: "If the remaining set contains multiple records or no records, Assertion Record Discovery terminates and BIMI processing MUST NOT be performed for this message." No TXT record at all is FAIL, "No BIMI record"; zero or several matching records among other TXT records are FAIL, "Publish exactly one BIMI record." ### Record syntax The record is read as a tag list, the DKIM syntax that [§4.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3) adopts. The version tag decides whether the record counts: "It MUST be the first tag in the list." Its value must be exactly `BIMI1`. A tag that appears twice fails the record, following [RFC 6376 §3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2): "if a tag name does occur more than once, the entire tag-list is invalid." A part without `=` fails as "Malformed tag". Unknown tags are ignored, as §4.3 requires. `l=` must start with `https://`, otherwise FAIL, "No logo URL". [§7.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.3) step 1: "The bimi-location entry MUST be a URI with a HTTPS transport." An empty `l=` gets the same finding, including the declination record `v=BIMI1; l=; a=;` that [§4.3.1](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3.1) defines as an explicit refusal; the tool does not name declination separately. A record without `a=` is CHECK, "No certificate (a=)". The tag is OPTIONAL in §4.3, so this is a Tamperbox reminder that some providers require a mark certificate. `a=` is not tested for HTTPS in the browser; the server refuses to fetch any URL that is not HTTPS. `avp=` is read and not judged; `lps=` is ignored. ### Fetching the logo and the certificate The server fetches a URL only if it is exactly the `l=` or `a=` value of the domain's single record. Each condition below fails the fetch, which is FAIL, "Logo not checked" or "Certificate not checked", with the reason. | Condition | Source | | --- | --- | | The URL is not HTTPS | [BIMI draft §4.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3), HTTPS only for `l=` and `a=` | | The URL has a custom port, credentials or a fragment | Tamperbox | | The host resolves to any non-public address | Tamperbox, server safety | | The server answers with a redirect | Tamperbox; none of the drafts addresses redirects | | The logo is not served as `image/svg+xml` | Tamperbox, standing in for the SVG-only rule of [§4.3.2](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3.2) | | The file exceeds 256 KiB | [§7.6](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.6) step 1 allows a size limit applied at retrieval | | The certificate file has no `BEGIN CERTIFICATE` block | [VMC draft §3.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-3.3): "Certificates fetched from the hosting service MUST be in PEM encoding" | The fetch uses the server's standard HTTPS client without turning off TLS certificate verification, and sends no cookies, credentials or visitor headers. ### SVG Tiny PS checks The logo is checked as text with pattern matching; it is neither parsed as XML nor rendered for the checks. | Check | FAIL title | Source | | --- | --- | --- | | Root `svg` element present | Not an SVG document | [BIMI draft §7.6](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.6) step 2 | | `baseProfile="tiny-ps"` | baseProfile is not tiny-ps | [SVG Tiny PS draft §2.1](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.1) | | `version="1.2"` | version="…" | [SVG Tiny PS draft §2.1](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.1) | | A `title` element with text | No `` | [SVG Tiny PS draft §2.1](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.1) | | Square `viewBox`, width equal to height, over zero | viewBox is not square | [BIMI Group SVG guidance](https://bimigroup.org/creating-bimi-svg-logo-files/) | | No `x` or `y` on the root | x or y on `<svg>` | [SVG Tiny PS draft §6.2](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-6.2) and the root element in [§7](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-7) | | No `script`, `foreignObject`, `image`, animation elements, event attributes, or `href` not starting with `#` | Contains … | [SVG Tiny PS draft §2.3](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.3) | | At most 32 KiB in UTF-8 | N KiB | [SVG Tiny PS draft §2.4](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.4) | #### The rules behind the SVG verdict §2.1 requires the profile attributes and the title: "The `<title>` element MUST be present and its contents MUST NOT be empty." §2.3 lists the forbidden image, scripting, linking and animation sections, which "MUST NOT be present in an SVG Tiny PS document". §2.4 is softer, "SHOULD NOT exceed 32 kilobytes", measured uncompressed; the tool counts 32,768 bytes and makes an excess FAIL. The square rule is BIMI Group guidance, "The image should be a square aspect ratio", which the tool also makes FAIL. #### What the SVG checks leave out Not checked: the `xmlns` attribute, a single title of at most 64 characters (§2.1), the `switch` element and the fixed values of `zoomAndPan` and similar attributes (§2.3), at least two colours (§2.4), and full validation against the RELAX NG schema in §7. An SVGZ file is not decompressed. ### Mark certificate checks Only the first certificate in the PEM is decoded, locally in the browser. | Check | Result | Source | | --- | --- | --- | | Logotype extension, OID 1.3.6.1.5.5.7.1.12 | FAIL "No logotype extension" when absent | [VMC draft §4.1](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.1); OID from [RFC 9399 §4.1](https://www.rfc-editor.org/rfc/rfc9399#section-4.1) | | Validity window, notBefore to notAfter inclusive | FAIL "Expired …" or "Not valid until …" | [RFC 5280 §4.1.2.5](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5); [VMC draft §4.5](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.5) | | Under 30 days to notAfter | CHECK "Valid until …" | Tamperbox | | The checked domain among the DNS subject alternative names, ignoring case | FAIL "Does not name X" | [VMC draft §4.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.3); [RFC 5280 §4.2.1.6](https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6) | | Trust not evaluated | CHECK "Certificate trust not verified" on every certificate | [VMC draft §5.1](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-5.1) | #### The rules behind the certificate verdict VMC draft §4.1: "Verified Mark Certificates MUST use logotype extension to carry the Indicators in the certificate". RFC 5280 §4.1.2.5: "The validity period for a certificate is the period of time from notBefore through notAfter, inclusive." Two-digit UTCTime years under 50 are read as 20YY, as the same section requires. VMC draft §4.3: "A Verified Mark Certificate MUST define one or more Subject Alternative Name (SAN) extension dNSName domain". #### What the certificate checks leave out VMC draft §5.1 lists what a receiver MUST verify; the tool performs none of these steps: the path to a trusted BIMI root ([RFC 5280 §6.1](https://www.rfc-editor.org/rfc/rfc5280#section-6.1)), revocation ([RFC 5280 §6.3](https://www.rfc-editor.org/rfc/rfc5280#section-6.3)) and the CRL distribution point of §4.5, the Certificate Transparency proof of §4.6, and the BIMI extended key usage of [§4.4](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.4). The SVG inside the logotype extension is not extracted or compared with the `l=` logo ([§5.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-5.3) step 7). Name matching differs from [§5.2](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-5.2): a SAN of the form `default._bimi.<domain>` or an organizational domain that §5.2 accepts is reported as "Does not name X". ### DMARC record The server reads the exact name `_dmarc.<domain>`. There is no DNS tree walk to the organizational domain, which [RFC 9989 §4.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.10.1) performs when the Author Domain has no record, so a subdomain that inherits its policy shows "No DMARC record". Records that start with `v=DMARC1` are kept. Several are FAIL, "Multiple DMARC records", matching [§4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10) step 2: "If multiple DMARC Policy Records are returned for a single target, they are all discarded." A record with a syntax failure, such as a `p` value outside none, quarantine and reject or a missing `p`, is FAIL, "Invalid DMARC record". [§4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) treats a missing `p` as `p=none`; both readings fail BIMI. A failed lookup is CHECK, "DMARC not checked", and never claims enforcement. ### DMARC policy rule The policy passes only when `p` is `quarantine` or `reject`, `t` is not `y`, and `sp` is not `none`, compared without regard to case. The conditions come from [BIMI draft §7.1](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.1): - Step 7: "If the DMARC [RFC7489] policy for the Author Domain or Author Organizational Domain is p=none then BIMI processing MUST NOT be performed for this message." - Step 8: "and that subdomain policy is sp=none then BIMI processing MUST NOT be performed for this message." - Step 9, for `p=quarantine`: "then that tag MUST be pct=100". The FAIL title names the condition that blocks: "DMARC p=none blocks the logo", "DMARC t=y blocks the logo" or "DMARC sp=none blocks the logo". Steps 1 to 6 of §7.1 judge a delivered message's DMARC result and cannot be checked from DNS. #### pct and t under RFC 9989 The checker evaluates current DMARC enforcement: `pct` is ignored under [RFC 9989 appendix A.6](https://www.rfc-editor.org/rfc/rfc9989#appendix-A.6), and `t=y` conservatively blocks readiness because it requests testing. This differs from the BIMI draft's legacy pct condition and does not prove eligibility at providers that still enforce that condition. ## Standards and conformance BIMI is not an RFC. The tool follows Internet-Drafts for BIMI itself, the logo profile and the mark certificate, plus the BIMI Group's published guidance where the code applies it, and RFCs for DMARC, certificates and record syntax. Domain lookups and fetches run on the Tamperbox server; every rule is evaluated in the browser on what came back, or on what you pasted. ### BIMI draft -14 [draft-brand-indicators-for-message-identification-14](https://datatracker.ietf.org/doc/draft-brand-indicators-for-message-identification/), 1 May 2026, is an individual Internet-Draft. It "is not endorsed by the IETF and has no formal standing", expires on 2 November 2026, and still cites the obsoleted RFC 7489 for DMARC. | Section | Requirement | What the tool does | | --- | --- | --- | | [§4](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4) | Join multiple TXT strings as SPF does | Joined without spaces | | [§4.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3) | `v=BIMI1` first, exact; unknown tags ignored; HTTPS URIs | Implemented; `a=` HTTPS enforced only by the server fetch | | [§4.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3) | "Mail receivers MUST NOT attempt to fix syntactical or capitalization errors" | Differs: a pasted record's tag names are read without regard to case, so `V=BIMI1` passes | | [§4.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3) | ABNF allows spaces around `=` in `v=BIMI1` | Differs: a published `v = BIMI1` is not recognised | | [§4.3.1](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3.1) | Empty `l=` and `a=` declines BIMI | Reported as "No logo URL" | | [§4.4](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.4), [§4.5](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.5) | Selectors and local-part selectors | Only `default` | | [§7.1](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.1) | DMARC policy conditions, steps 7 to 9 | Checked on the exact `_dmarc` record; test mode blocks readiness and obsolete pct does not limit current DMARC enforcement | | [§7.2](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.2) | Discard other versions; exactly one record | Implemented; no organizational-domain fallback | | [§7.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.3) | `l=` is an HTTPS URI | Implemented | | [§7.6](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.6) | Size limit; valid SVG | 256 KiB fetch cap, 32 KiB check; root element present, no XML validation | Header fields (§5) and Authentication-Results (§7.7) concern delivered messages and are outside a DNS check. ### SVG Tiny PS draft -12 [draft-svg-tiny-ps-abrotman-12](https://datatracker.ietf.org/doc/draft-svg-tiny-ps-abrotman/), 1 May 2026, is an individual Internet-Draft with no formal standing that expires on 2 November 2026. The BIMI draft defers SVG rules to it ("Further restrictions apply to the SVG; these are documented elsewhere", §4.3.2). | Section | Requirement | What the tool does | | --- | --- | --- | | [§2.1](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.1) | `version="1.2"`, `baseProfile="tiny-ps"`, `xmlns` | First two checked; `xmlns` not checked | | [§2.1](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.1) | Non-empty title, exactly once, up to 64 characters | Presence and text checked; count and length not checked | | [§2.2](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.2) | Restrictions on paths, shapes, text, painting | Not checked except through the animation ban | | [§2.3](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.3) | No image, multimedia, interactivity, linking, scripting, animation | `script`, `foreignObject`, `image`, animation elements, `on…` attributes and non-`#` `href` checked; `switch` and attribute values not | | [§2.4](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.4) | Up to 32 KB uncompressed (SHOULD); at least two colours | Size enforced as FAIL; colours not checked | | [§6.2](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-6.2), [§7](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-7) | No `x`/`y` on the root; RELAX NG schema | `x`/`y` checked; schema not applied | ### VMC draft -11 [draft-fetch-validation-vmc-wchuang-11](https://datatracker.ietf.org/doc/draft-fetch-validation-vmc-wchuang/), 1 May 2026, is an individual Internet-Draft with no formal standing that expires on 2 November 2026. The content of the logotype extension is defined by the BIMI Group's [VMC Guidelines](https://bimigroup.org/resources/VMC_Guidelines_latest.pdf), which the tool does not check. | Section | Requirement | What the tool does | | --- | --- | --- | | [§3.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-3.3) | PEM with the full issuance chain | PEM required; only the first certificate read; the count is shown | | [§4.1](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.1) | Logotype extension | Presence checked; content not decoded | | [§4.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.3), [§5.2](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-5.2) | SAN dNSName matches the record's domain or selector name | Exact domain only | | [§4.4](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.4) | BIMI extended key usage | Not checked | | [§4.5](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.5) | Validity dates; CRL distribution point | Dates checked; CRL point not checked | | [§4.6](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.6) | SCT extension | Not checked | | [§5.1](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-5.1), [§5.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-5.3) | Path, revocation, CT, logo comparison | Not checked; reported as "Certificate trust not verified" | ### BIMI Group guidance The BIMI Group publishes operational guidance, not a standard. The tool applies two items from it: the square aspect ratio from [Creating BIMI SVG logo files](https://bimigroup.org/creating-bimi-svg-logo-files/), while the legacy `pct=100` condition in the [implementation guide](https://bimigroup.org/implementation-guide/) is not a current DMARC sampling rule. The guide also asks for enforcement on subdomains; the tool tests only that `sp` is not `none`. ### RFC 9989, DMARC [RFC 9989](https://www.rfc-editor.org/info/rfc9989), May 2026, Proposed Standard, obsoletes RFC 7489 and RFC 9091; RFC 9990 and RFC 9991 complete the replacement of RFC 7489 for reporting. | Section | Requirement | What the tool does | | --- | --- | --- | | [§4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) | `v=DMARC1` first; `p`, `sp`, `np` values; `t` test mode | Values validated; `t=y` blocks readiness | | [§4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10) | Several records for one name are discarded | FAIL, "Multiple DMARC records" | | [§4.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.10.1) | Tree walk when the Author Domain has no record | Not performed | | [Appendix A.6](https://www.rfc-editor.org/rfc/rfc9989#appendix-A.6) | `pct` removed | Ignored for current DMARC grading; legacy BIMI receiver compatibility is not established | ### Certificate and record syntax RFCs [RFC 5280](https://www.rfc-editor.org/info/rfc5280), Proposed Standard, is updated by RFC 6818, 8398, 8399, 9549, 9598, 9608, 9618, 9925 and 10007; the tool uses §4.1.2.5 for dates and §4.2.1.6 for names, and none of §6. [RFC 9399](https://www.rfc-editor.org/info/rfc9399), Proposed Standard, May 2023, obsoletes RFC 3709 and RFC 6170, which the VMC draft still cites; the tool uses its §4.1 OID. [RFC 6376](https://www.rfc-editor.org/info/rfc6376), Internet Standard, supplies the tag-list rule of §3.2, and [RFC 7208](https://www.rfc-editor.org/info/rfc7208), Proposed Standard, the string joining of §3.3. ## Finding reference Each finding the checker can emit, grouped by the part of BIMI it judges, with what it means for the logo and the section it rests on. "none" marks a Tamperbox finding. ### BIMI record The TXT record at `default._bimi` and what it points to. | Finding | Severity | What it means for the logo | Fix | Source | | --- | --- | --- | --- | --- | | No BIMI record | FAIL | Providers have nothing to fetch | Publish the record | [BIMI §7.2](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.2) | | Publish exactly one BIMI record. | FAIL | Discovery stops | Keep one `v=BIMI1` record | [BIMI §7.2](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.2) | | The version tag must be first., A BIMI record starts with v=BIMI1. | FAIL | The record is ignored | Start with `v=BIMI1` | [BIMI §4.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3) | | Malformed tag: X, X appears twice | FAIL | The record is unreadable | Publish one valid record | [RFC 6376 §3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2) | | No logo URL | FAIL | Nothing to fetch | Set l= to an https:// URL | [BIMI §7.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.3) | | Published resources not checked | CHECK | Only a pasted record was checked | Enter the domain | none | ### Logo file The SVG at the `l=` address, against the SVG Tiny Portable/Secure profile. | Finding | Severity | What it means for the logo | Fix | Source | | --- | --- | --- | --- | --- | | Logo not checked | FAIL | Providers cannot fetch the logo either | Serve it at the URL, over HTTPS, as image/svg+xml, without redirect | [BIMI §7.5](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.5) | | Not an SVG document | FAIL | Not an SVG | Publish the SVG file | [BIMI §7.6](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.6) | | baseProfile is not tiny-ps, version="…", No `<title>` | FAIL | Providers refuse the logo | Export as SVG Tiny PS; Heal it fixes attributes | [SVG Tiny PS §2.1](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.1) | | viewBox is not square | FAIL | Cropped or refused | Pad the viewBox | [BIMI Group](https://bimigroup.org/creating-bimi-svg-logo-files/) | | x or y on `<svg>` | FAIL | Providers refuse the logo | Remove the attributes | [SVG Tiny PS §6.2](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-6.2) | | Contains … | FAIL | Providers refuse the logo | Remove the element | [SVG Tiny PS §2.3](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.3) | | N KiB (over 32) | FAIL | Providers may refuse it | Simplify the artwork | [SVG Tiny PS §2.4](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.4) | ### Mark certificate The PEM at the `a=` address, when one is published. | Finding | Severity | What it means for the logo | Fix | Source | | --- | --- | --- | --- | --- | | Certificate not checked | FAIL | Providers that require a certificate show nothing | Serve the PEM at the URL | [VMC §3.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-3.3) | | No logotype extension | FAIL | Not a mark certificate | Publish a VMC or CMC | [VMC §4.1](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.1) | | Expired …, Not valid until … | FAIL | Providers stop showing the logo | Renew | [RFC 5280 §4.1.2.5](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5) | | Does not name X | FAIL | The certificate is for another domain | Request one that names the domain | [VMC §4.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.3) | | Certificate validity dates are missing or invalid, The certificate validity dates could not be read. | FAIL | The file is not a usable certificate | Publish the issued PEM | [RFC 5280 §4.1.2.5](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5) | | No PEM certificate found…, The certificate could not be read. | FAIL | The file is not a readable certificate | Publish the issued PEM | [VMC §3.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-3.3) | | Valid until … (under 30 days) | CHECK | Expires soon | Renew now | none | | Certificate trust not verified | CHECK | Trust, revocation and logo hash are outside this check | Nothing here | [VMC §5.1](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-5.1) | | No certificate (a=) | CHECK | Some providers require one | Add a mark certificate | none | ### DMARC and the overall result BIMI is shown only on top of an enforcing DMARC policy. | Finding | Severity | What it means for the logo | Fix | Source | | --- | --- | --- | --- | --- | | DMARC p=… blocks the logo | FAIL | Providers show logos only on top of enforcement | Enforce DMARC | [BIMI §7.1](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.1) step 7 | | DMARC sp=none blocks the logo | FAIL | Subdomains are unprotected | Remove sp=none | [BIMI §7.1](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.1) step 8 | | DMARC t=y blocks the logo | FAIL | Testing requests reduced enforcement | Review reports before disabling test mode | [RFC 9989 §4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7), conservative Tamperbox readiness rule | | No DMARC record | FAIL | No policy at this exact name | Publish `_dmarc` | [RFC 9989 §4.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.10.1) | | Multiple DMARC records | FAIL | Receivers discard them all | Keep one record | [RFC 9989 §4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10) | | Invalid DMARC record | FAIL | BIMI needs a valid, enforcing record | Fix DMARC first | [RFC 9989 §4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) | | DMARC not checked | CHECK | The lookup failed | Retry | none | | Nothing to fix | PASS | Every part checked passes | | none | ## Guide ### The logo does not appear 1. Reach DMARC enforcement first: quarantine or reject at 100%, with `sp` unset or matching. The DMARC checker's path to enforcement writes each step. 2. Publish the logo as SVG Tiny PS at a stable HTTPS URL, served as `image/svg+xml` without redirects, and the certificate as a PEM at another. 3. Publish `default._bimi.<domain> TXT "v=BIMI1; l=<logo URL>; a=<certificate URL>"`. 4. Check the domain here. Every step in Basic readiness should pass; then allow a few days for providers to pick up the change, and remember that each one applies its own rules. ### Exporting the logo Design tools export SVG 1.1 by default. Export as SVG Tiny 1.2, set `baseProfile="tiny-ps"`, give the artwork a square artboard, add a `title` with the brand name, and remove embedded raster images, scripts and animation. Paste the file here to confirm it passes; Heal it fixes the root attributes, pads the viewBox and adds a placeholder title that you should replace with the brand name. ### The logo or certificate cannot be fetched Serve each file at exactly the URL in the record, over HTTPS on the default port, without redirects. A CDN that redirects to a versioned asset, an SVG served as `text/plain`, and a certificate URL that returns an HTML error page are the usual causes. ### The certificate Obtain a Verified Mark Certificate or a Common Mark Certificate from an issuing authority; it carries the logotype extension and names your domain. Put its expiry in a calendar and renew before it. ### Break it cases Each case is built from the logo or record you pasted or the domain publishes. | Case | What it does | Heal it offers (pasted SVG) | | --- | --- | --- | | Not Tiny PS | Removes baseProfile and sets version 1.1 | Set the Tiny PS profile on `<svg>` | | Has a script | Inserts a script element | Remove scripts and handlers | | Not square | Doubles the viewBox width | Pad the viewBox to a square | | No title | Removes the title element | Add a `<title>` | | Record without a logo | Empties `l=` in the record | Nothing: set the URL yourself | ## Worked example The page opens on a live check of `tamperbox.dev`. Its published records and findings can change over time. For the deterministic walkthrough below, enter `harbor-supply.example`. This reserved `.example` domain is answered from synthetic data in your browser; it sends no live lookup. Its record names a square SVG Tiny PS logo and a mark certificate, both of which pass; its DMARC record is `p=none`. **DMARC p=none blocks the logo: this DMARC policy requirement is not met.** The findings are the DMARC blocker (FAIL, with a button to the DMARC checker) and "Certificate trust not verified" (CHECK). Replace the sample with your own domain and every section, card and link is rewritten for it. ## For agents The Tamperbox MCP server runs the same checks. Search its catalog for the BIMI operation, inspect the input schema, and call it with the domain. Keep the warning block with any conclusion: - Certificate trust, revocation and the embedded logo's hash are not verified; the SVG checks are text checks, not schema validation. - Only the default selector is looked up; the exact `_dmarc` name is read without inheritance. - Each mailbox provider decides whether to show a logo; passing every check does not guarantee display. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the domain travels. ## Limits - Text checks of the SVG; no XML parsing, schema validation or rendering-based validation. - Certificate fields only; no chain, revocation, extended key usage, Certificate Transparency or logo hash. - Default selector only; exact `_dmarc` name only, without the RFC 9989 tree walk. - The DMARC `t=` tag is ignored, and a declination record is reported as a missing logo URL. - One DNS answer and one fetch per file, at one moment. - Nothing is stored. ## References ### BIMI specifications - [draft-brand-indicators-for-message-identification-14](https://datatracker.ietf.org/doc/draft-brand-indicators-for-message-identification/), Brand Indicators for Message Identification (BIMI), 1 May 2026. Individual Internet-Draft, no formal standing, expires 2 November 2026. Sections used: [§4](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4), [§4.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3), [§4.3.1](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3.1), [§4.3.2](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.3.2), [§4.4](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.4), [§4.5](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-4.5), [§7.1](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.1), [§7.2](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.2), [§7.3](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.3), [§7.5](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.5), [§7.6](https://www.ietf.org/archive/id/draft-brand-indicators-for-message-identification-14.html#section-7.6). - [draft-svg-tiny-ps-abrotman-12](https://datatracker.ietf.org/doc/draft-svg-tiny-ps-abrotman/), SVG Tiny Portable/Secure, 1 May 2026. Individual Internet-Draft, no formal standing, expires 2 November 2026. Sections used: [§2.1](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.1), [§2.3](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.3), [§2.4](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-2.4), [§6.2](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-6.2), [§7](https://www.ietf.org/archive/id/draft-svg-tiny-ps-abrotman-12.html#section-7). - [draft-fetch-validation-vmc-wchuang-11](https://datatracker.ietf.org/doc/draft-fetch-validation-vmc-wchuang/), Fetch and Validation of Verified Mark Certificates, 1 May 2026. Individual Internet-Draft, no formal standing, expires 2 November 2026. Sections used: [§3.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-3.3), [§4.1](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.1), [§4.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.3), [§4.5](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-4.5), [§5.1](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-5.1), [§5.2](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-5.2), [§5.3](https://www.ietf.org/archive/id/draft-fetch-validation-vmc-wchuang-11.html#section-5.3). ### RFCs - [RFC 9989](https://www.rfc-editor.org/info/rfc9989), DMARC, May 2026, Proposed Standard; obsoletes RFC 7489 and RFC 9091. Sections used: [§4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7), [§4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10), [§4.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.10.1), [§9.3](https://www.rfc-editor.org/rfc/rfc9989#section-9.3), [Appendix A.6](https://www.rfc-editor.org/rfc/rfc9989#appendix-A.6). - [RFC 7489](https://www.rfc-editor.org/info/rfc7489), DMARC, March 2015, Informational; obsoleted by RFC 9989, RFC 9990 and RFC 9991. Cited only because the BIMI draft still names it. - [RFC 5280](https://www.rfc-editor.org/info/rfc5280), X.509 certificate and CRL profile, May 2008, Proposed Standard; updated by RFC 6818, 8398, 8399, 9549, 9598, 9608, 9618, 9925 and 10007. Sections used: [§4.1.2.5](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5), [§4.2.1.6](https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6); [§6.1](https://www.rfc-editor.org/rfc/rfc5280#section-6.1) and [§6.3](https://www.rfc-editor.org/rfc/rfc5280#section-6.3) are named as not performed. - [RFC 9399](https://www.rfc-editor.org/info/rfc9399), Logotypes in X.509 certificates, May 2023, Proposed Standard; obsoletes RFC 3709 and RFC 6170. Section used: [§4.1](https://www.rfc-editor.org/rfc/rfc9399#section-4.1). - [RFC 6376](https://www.rfc-editor.org/info/rfc6376), DKIM signatures, September 2011, Internet Standard; updated by RFC 8301, 8463, 8553 and 8616. Section used: [§3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2). - [RFC 7208](https://www.rfc-editor.org/info/rfc7208), SPF, April 2014, Proposed Standard; updated by RFC 7372, 8553 and 8616. Section used: [§3.3](https://www.rfc-editor.org/rfc/rfc7208#section-3.3). ### Guidance and related tools - [BIMI Group implementation guide](https://bimigroup.org/implementation-guide/), for DMARC enforcement and `pct`; guidance, not a standard. - [Creating BIMI SVG logo files](https://bimigroup.org/creating-bimi-svg-logo-files/), BIMI Group, for the square aspect ratio. - [VMC Guidelines](https://bimigroup.org/resources/VMC_Guidelines_latest.pdf), BIMI Group, which define the mark certificate content the tool does not check. - [DMARC Checker & Generator](https://docs.tamperbox.dev/tools/dmarc-checker/), for the path to enforcement. --- # Broken Link Checker How the broken link checker collects every link, image and script on one page, requests each from the Tamperbox server, sorts them into broken, unclear, redirected and working, and how to fix each kind. Canonical: https://docs.tamperbox.dev/tools/broken-link-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: The public http or https address of one page that answers with HTML Outputs: A verdict with the broken count, a summary bar, every address with its status, place on the page, line and final address, and findings for broken, redirected, unclear and http:// links Limitations: One page's initial HTML as a signed-out visitor sees it; 401, 403, 429 and timeouts are reported as unclear, not broken; at most 300 addresses The tool page is [tamperbox.dev/broken-link-checker](https://tamperbox.dev/broken-link-checker). It loads `tamperbox.dev` and waits for you to run a live check, says how many links are broken, and lists every address worst first. This page is the long version: what is collected, how each address is requested, how each result is sorted, and how to fix each kind. <div class="tb-callout"><strong>Where processing happens:</strong> typing an address is read in your browser only. Nothing is sent until you press Check links or Enter. Then the Tamperbox server fetches the page and requests each address on it, without cookies, and returns the completed result. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. Sample addresses on the reserved <code>.example</code> zone are answered in the browser from a fixture.</div> ## What the tool answers 1. **Which links on this page are broken?** Separately for links within the site, which you can fix, and links to other sites, which you can only update or remove. 2. **Which ones only look broken?** Refusals, rate limits and timeouts from sites that block automated requests, which may open fine in a browser. 3. **Which ones work only after a detour?** Links that redirect, with the address they end at. 4. **Where is each one?** Its landmark on the page (navigation, header, main content, footer, sidebar), its line in the HTML, what kind of element carries it, and how often it is used. ## Inputs ### A page address Type `example.com/pricing` or paste `https://example.com/pricing`. Without a scheme the address starts at `https://`. The path and query are kept, because the links of `/pricing` are not those of the home page; a fragment is dropped. The check is manual and costs real requests to other sites, so typing only says "Ready to check" and that up to 300 addresses take about half a minute. Nothing leaves the browser until you press **Check links** or Enter. A sample address on `.example` is answered at once from the fixture. Refused before any request: spaces, schemes other than http and https, `mailto:` and similar, user names and passwords (Heal it removes them), ports other than 80 and 443 (Heal it offers the standard port), IP addresses and single-label names. A pasted address loses surrounding quotes, angle brackets and trailing punctuation; text that is not an address stays as pasted so the error can explain it. A dropped `.txt` file is read in the browser. ## Reading the result ### Verdict and chips "n broken links on host, out of m checked." or "No broken links among m checked on host." The line under it counts what else was found: redirects, links that could not be checked, and links not requested. The chips (broken, redirected, unclear, working) scroll to the link list. Two items say where the input went: typing stays in the browser; Check links means our server fetches the page and its links. ### Findings Worst first: broken links within the site, broken links to other sites, redirected links, links that could not be checked, addresses still on `http://`. The findings show "Every link works" only when no other finding was produced and at least one address was checked; the tally separately counts working links. When other findings exist and more than one link works, an additional passing finding reports that working count. Two or more passing findings are grouped under an expandable **checks passed** row. A single passing finding stays visible. ### Summary One bar for the requested addresses, broken first, then unclear, redirected and working, with the counts in the legend. The meta line gives how many were requested and how long it took, and how many were over the limit. ### Links Every address, worst first, then by line. Filter chips show one kind at a time. Each row has the status (or the stage it stopped at), the link text or the element kind, the address, where it sits, its line, how often it is used, the final address after redirects, and the time. Sixty rows show at first; **Show n more** lists the rest. ### History History follows the current result evidence. Break it and Heal it record input changes, newest first. **Revert** restores the input before the latest recorded change; **Reset input** restores the input before the first retained change and clears the list. **Restore input before this break** under Heal it also reverts the latest change. These actions reload and check the restored input. Restoring a public address can therefore send a new request, including on the two tools whose ordinary typing waits for a run button. Editing or pasting a new input clears History. The list lives in the current page; it is not saved monitoring data and does not restore an old network response. ### Take it further Only links with an available result value appear. | Follow-up | Value carried | When offered | | --- | --- | --- | | [Redirect Checker](https://tamperbox.dev/redirect-checker) | First redirected link's original URL | A redirected link was found | | [Website Down Checker](https://tamperbox.dev/website-down-checker) | First broken link's URL | A broken link was found | | [SSL Checker](https://tamperbox.dev/ssl-checker) | Host of the first connection/TLS failure | A link failed at either of those stages | ### Related checks and input transfer Check the rest carries the current address to a sibling tool. Take it further carries the specific value listed above. Pasted file contents are not transferred through these links. Transfers temporarily use browser `sessionStorage` with a one-use random token in the URL fragment; the input itself is not in the URL. The destination accepts a transfer for less than one minute and removes the token. Manual destination tools wait for their run button or Enter. Each destination collects new evidence. A follow-up link does not confirm the original verdict or repair the remote site. ### Result cards Six expandable cards below the result explain its meaning, give a beginner explanation, offer an agent prompt, describe good practice, suggest fixes and state limitations. Their text follows the current result; it is not another measurement. Open a card for its full explanation and the relevant [Method](#method) or [Guide](#guide). The agent prompt can be copied for review; copying it does not run a repair or send it to an agent. ## Method The page calls `/api/web/links`. The current server collects the results and returns one JSON object containing `page`, `links`, `skipped` and `done`. The browser client turns those collections into events for its renderer; this does not mean each destination response is streamed from the server as it finishes. ### Fetching the page The page is requested with `GET`, `Accept: text/html,application/xhtml+xml;q=0.9,*/*;q=0.8`, the user agent `TamperboxBot/1.0`, no cookies, following up to 10 redirects and reading the first 512 KiB. A response that is not `text/html` or `application/xhtml+xml` has no links to collect. If the page itself answers 400 or above, the check stops with an error naming the status, because an error page's links are not the page's links. ### Collecting addresses The HTML is parsed with a full HTML parser (parse5, which follows the [HTML Standard's parsing algorithm](https://html.spec.whatwg.org/multipage/parsing.html)), with source positions, so each address keeps its line. Collected: | Element | Attribute | Specification | | --- | --- | --- | | `a`, `area` | `href` | [HTML, section 4.6.1](https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements) | | `img`, `script`, `iframe`, `source`, `video`, `audio` | `src` | [HTML, embedded content](https://html.spec.whatwg.org/multipage/embedded-content.html) | | `img` | first candidate of `srcset` | [HTML, section 4.8.4.2](https://html.spec.whatwg.org/multipage/images.html#srcset-attributes) | | `link` with rel `stylesheet`, `icon` or `preload` | `href` | [HTML, section 4.6.6](https://html.spec.whatwg.org/multipage/links.html#linkTypes) | Each address is resolved against the document's `<base href>` when there is one ([HTML, section 4.2.3](https://html.spec.whatwg.org/multipage/semantics.html#the-base-element)), otherwise against the final page address, as a URL reference ([RFC 3986, section 5.2](https://www.rfc-editor.org/rfc/rfc3986#section-5.2)). The fragment is removed ([RFC 3986, section 3.5](https://www.rfc-editor.org/rfc/rfc3986#section-3.5): it is never sent to a server). Repeated addresses are requested once and shown as "used n times". The first 300 unique addresses are requested; the rest are counted as over the limit. Listed but not requested: `mailto:`, `tel:`, `sms:`, `javascript:`, `data:` and any other non-HTTP scheme, a fragment that points back into the same page, and values that are not valid URLs. Not collected at all: addresses inside CSS, `form` actions, video posters and canonical links. A link counts as within the site when its origin (scheme, host and port, [RFC 6454, section 4](https://www.rfc-editor.org/rfc/rfc6454#section-4)) matches the page's. An `http://` link to your own HTTPS site therefore counts as another site. ### Requesting each address 1. **HEAD first.** [RFC 9110, section 9.3.2](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.2): HEAD "is identical to GET except that the server MUST NOT send content in the response". It answers the question without downloading pages and images. 2. **GET when HEAD is refused.** If HEAD ends at 403, 405 (Method Not Allowed) or 501 (Not Implemented), which servers send when they do not support HEAD, the address is requested again with GET. Bodies are never read. 3. **Redirects.** Up to 5 per address, each `Location` resolved and checked like the first address ([RFC 9110, section 15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4)). A loop, more than 5, a redirect without `Location`, or one to a private address or another port stops that address. 4. **Public targets only.** Each host is looked up in public DNS first; an address that resolves to a private range, an IP address written in the link, or a port other than 80 and 443 is not requested and is listed as "Not checked". 5. **Budgets.** 8 seconds per address, redirects included. At most 8 addresses at once and 2 at a time per host, so one site is not flooded. The whole check stops at 45 seconds and 1,000 requests; addresses not reached are marked with the time limit. ### Sorting results | Rule | Kind | Severity | | --- | --- | --- | | Final status 400 or above, except 401, 403 and 429 | Broken | FAIL | | Host does not resolve, connection refused or failed, redirects loop or exceed 5 | Broken | FAIL | | 401, 403 or 429 | Could not check | INFO | | Timeout of the address, or the overall time limit | Could not check | INFO | | Target not allowed (private address, other port) | Could not check | INFO | | Answered below 400 after one or more redirects | Redirected | CHECK | | Answered below 400 directly | Working | PASS | | Non-HTTP scheme, same-page anchor, invalid URL | Not checked | listed only | Why 401, 403 and 429 are not broken: [RFC 9110, section 15.5.2](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.2) (401) and [15.5.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.4) (403) mean the server understood the request and refused it to this client; [RFC 6585, section 4](https://www.rfc-editor.org/rfc/rfc6585#section-4) (429) means too many requests. A signed-in visitor, or any visitor not behind a bot filter, may get the page. A 404 ([section 15.5.5](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.5)) or 410 ([section 15.5.11](https://www.rfc-editor.org/rfc/rfc9110#section-15.5.11)) reports that this server did not provide the resource to this request; authorization and routing can still affect another client. A link that redirects and then ends at 404 is broken, not redirected: the final answer decides. ## Standards and conformance ### RFC 9110, HTTP Semantics Implemented: HEAD as a bodiless GET (section 9.3.2) with GET as the fallback when a server does not implement HEAD; status classes (section 15) for the sorting rules; redirect following with `Location` (sections 10.2.2 and 15.4). Stricter than browsers: 5 redirects per link instead of about 20. More lenient than a strict reading: a 403 is not called broken, because the purpose is to find links that are broken for visitors, not for robots. RFC 9110 obsoletes RFC 7231. ### HTML Standard and RFC 3986, URLs Implemented: the elements and attributes in the table above, `<base href>`, URL reference resolution and fragment removal. Not implemented: every `srcset` candidate beyond the first, `<picture>` art direction, CSS `url()` references, and any URL a script writes after load, because scripts are not executed. ### RFC 6454, origins Used only to decide "within the site": same scheme, host and port. ## Finding reference The labels below organize this guide; the browser emits finding titles and statuses rather than these labels as stable machine identifiers. | Guide label | Severity | Title | What it means for visitors | Fix | | --- | --- | --- | --- | --- | | `broken-internal` | FAIL | n broken links within host | Dead ends on your own site; crawlers waste fetches | Correct the link, or redirect the old address | | `broken-external` | FAIL | n broken links to other sites | The page looks neglected; visitors leave with nothing | Update to the new address, an archived copy, or remove | | `redirects` | CHECK | n links redirect | One extra round trip each | Link to the final address shown | | `unclear` | INFO | n links could not be checked | May work in a browser; not proven broken | Open each in a browser | | `insecure` | INFO | n addresses use http:// | Links leave HTTPS; images and scripts are mixed content | Use https:// where supported | | `working` | PASS | Every link works, or n links work | | | | `none` | INFO | No links found | Nothing in the HTML; script-added links are not seen | Send links in the HTML | The page itself answering 400 or more is not a finding but an error: "Not checked: the page itself answered n, so there were no links to check." ## Guide ### Broken links within your site 1. Filter the list to Broken and read the line number and landmark of each. 2. A broken link in the navigation or footer is on every page: fix it in the template once. 3. A page that moved: update the link and add a 301 from the old address, so other sites' links keep working. 4. A broken script, style sheet or image after a deploy usually means cached HTML still points at old hashed asset names; purge the HTML cache. Confirm: press Check links again; Broken should be 0. Outside Tamperbox: `curl -sI -L --max-redirs 5 https://example.com/old-page | head -1`. ### Broken links to other sites 1. Search for the page's new address, or find it in an archive. 2. Update the link, or remove it if the content is gone. 3. A DNS failure means the other domain lapsed or the link has a typo in the host: `dig +short A other.example`. ### Links that could not be checked 1. Open each one in a browser. If it loads, leave it. 2. If it fails in the browser too, treat it as broken. 3. Rate limits (429) can clear with time; check again later. ### Redirected links Replace each link with the final address shown under it. The common ones are `http://` to `https://`, a missing trailing slash, and a site that moved. Use **Redirect chain of the first redirected link** to see each hop. ### Addresses on http:// Change them to `https://` where the other site supports it. For images and scripts on an HTTPS page, the [mixed content checker](https://tamperbox.dev/mixed-content-checker) shows what browsers block. ### Break it cases | Case | What it loads | What to look at | | --- | --- | --- | | Page not found | A sample page that answers 404 | The check stops: the page itself is broken | | Page with no links | A sample page with no links | No links found | | Page times out | A sample partner page that never answers | The check stops at the page fetch | | No such host | `nohost.` plus your own domain | The page's host does not resolve | Break it replaces the field with an adapted input or a labelled fixture. Use History to Revert the latest change or Reset input to the starting input; restoring a live address runs a new check. ## Worked example The page loads `https://tamperbox.dev/` and waits for **Check links**. Running it fetches the current home page and checks the bounded set of addresses extracted from its HTML. Counts and results are live evidence; the guide does not promise a fixed number of working or broken links. Read the source-page status before interpreting the link totals. Then filter Broken, Could not check and Redirected separately. For a broken internal address, use its source line and context to find the authored reference. For a redirect, inspect the final destination before updating the link. For 403 or 429, verify in a browser instead of assuming that the page was deleted. Check the omitted count and truncation flag before describing the page as fully checked. A zero-broken result applies only to the collected addresses. It does not verify fragment targets, script-created links or pages reached by following those links. Use a Break it fixture to examine a missing source page or a timeout without deliberately breaking the real site. ## For agents Use the Tamperbox MCP `search` tool to inspect the schema, then `execute` with `tamperbox.request` to call `POST /v1/tools/broken_link_checker`. Supply the required `url` field as a full public HTTP or HTTPS URL. The operation is named `broken_link_checker`; the browser page’s hyphenated identifier is not the API operation name. The response contains `page`, `links`, `skipped` and `done`. Preserve source truncation, omitted counts, per-link errors and budget limits. A completed response does not mean every address on the site was checked. Keep the input, observation time, source limitations and inconclusive results with any summary. Browser fixtures are demonstrations, not live MCP targets. Do not turn missing evidence into a passing check or infer that an inaccessible resource has been deleted. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/), [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) and [Security and privacy](https://docs.tamperbox.dev/reference/security/). ## Limits - One page, not a site. Up to 300 unique addresses, 8 seconds each, 45 seconds and 1,000 requests in all. - Scripts are not executed, so links added after load are not seen. - Only the first `srcset` candidate is checked; CSS references, form actions and posters are not collected. - Private addresses, IP addresses and ports other than 80 and 443 are not requested. - A site can refuse automated requests while it works for people. - Live checks are rate limited. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. ## References - [RFC 9110, HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110): [section 9.3.2](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.2) HEAD, [section 10.2.2](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.2) Location, [section 15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4) redirection, [section 15.5](https://www.rfc-editor.org/rfc/rfc9110#section-15.5) client errors. Obsoletes RFC 7231. - [RFC 6585, section 4](https://www.rfc-editor.org/rfc/rfc6585#section-4), 429 Too Many Requests. - [RFC 3986, URI Generic Syntax](https://www.rfc-editor.org/rfc/rfc3986): [section 3.5](https://www.rfc-editor.org/rfc/rfc3986#section-3.5) fragment, [section 5.2](https://www.rfc-editor.org/rfc/rfc3986#section-5.2) reference resolution. - [RFC 6454, The Web Origin Concept](https://www.rfc-editor.org/rfc/rfc6454#section-4), section 4. - [HTML Standard](https://html.spec.whatwg.org/multipage/): [links](https://html.spec.whatwg.org/multipage/links.html), [the base element](https://html.spec.whatwg.org/multipage/semantics.html#the-base-element), [srcset](https://html.spec.whatwg.org/multipage/images.html#srcset-attributes), [parsing](https://html.spec.whatwg.org/multipage/parsing.html). --- # CAA Lookup How the CAA Lookup finds the CAA records that govern a name, climbing to the closest parent that has some, reads which certificate authorities may issue ordinary and wildcard certificates, compares them with certificates already in the public logs, and how to write and confirm a policy. Canonical: https://docs.tamperbox.dev/tools/caa-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A DNS name, or CAA records to paste Outputs: A verdict naming the CAs allowed, findings, who may issue ordinary and wildcard certificates, where refusals are reported, each record explained, and the answer as dig-style text Limitations: CAs check CAA only at issuance; the certificate-log search can miss certificates or be unavailable, and a logged issuer outside the policy is not proof of mis-issuance; account and validation-method parameters are not evaluated The tool page is [tamperbox.dev/caa-lookup](https://tamperbox.dev/caa-lookup). It opens on `harbor-supply.example`, a sample domain on the reserved `.example` zone that allows two certificate authorities, with sample certificate-log data beside it. This page is the long version: how a CA finds the records that apply, what each tag means, how the tool compares the policy with the certificates already issued, and how to write a policy that matches the services you use. <div class="tb-callout"><strong>Where processing happens:</strong> a name is sent to the Tamperbox server, which asks Cloudflare for CAA records over DNS over HTTPS, one name at a time up the tree, and searches public certificate logs (crt.sh) for the registrable domain. Pasted records are read in your browser; nothing is looked up for them. Sample names under <code>.example</code> are answered in the browser. Ordinary lookup results are not persisted by this page. An explicit handoff temporarily stores its value in session storage for one-use transfer.</div> ## What the tool answers CAA records name the certificate authorities that may issue certificates for a domain ([RFC 8659](https://www.rfc-editor.org/rfc/rfc8659)). Every publicly trusted CA must check them before issuing. The tool answers: 1. **Which records apply to this name?** Its own, or those of the closest parent that has some. 2. **Who may issue ordinary certificates, and who wildcard ones?** 3. **Where are refused requests reported?** The iodef contact. 4. **Does anything block issuance by accident?** An unknown critical tag, or an empty issue value. 5. **Do the certificates already issued fit the policy?** Issuers in the public certificate logs that the policy would now refuse. It does not ask a CA what it would do, does not evaluate account or validation-method parameters, and cannot revoke anything: CAA governs issuance only. ## Inputs ### A name `example.com`, `www.example.com`, `api.shop.example.com`. The lookup runs when you stop typing, or on Enter. A pasted address or email address is reduced to its host or domain. ### Pasted records Anything with a space or a quote is read as records, in the browser: dig answers, zone file lines, or bare `flags tag "value"` lines. A record that is not flags, tag and value is refused: "A CAA record is flags, tag and value, such as 0 issue "letsencrypt.org"." No parent is climbed and no certificate log is searched for pasted records. ### Files Drop a `.txt` file anywhere on the page. ## Reading the result ### Verdict and chips "Let's Encrypt and Sectigo may issue for example.com." with "by the records at example.com" when they were inherited, and a line naming the CAs seen in the certificate logs. "No CAA records: any certificate authority may issue.", "No CA may issue ordinary certificates", or "Critical CAA tag needs review:" otherwise. The chips count the CAs and name each logged issuer the policy would refuse. ### Where your input goes Pasted records stay in the browser; a name means CAA queries and one certificate-log search from our server. ### Findings Failures, checks and notes first, the pass last. ### CAA records A summary of who may issue ordinary certificates, who may issue wildcard certificates, and where refusals are reported; then one row per record with its tag, value (marked Critical when the flag is set) and meaning. ### DNS response The answer as dig-style text, with a copy button. ### History and Heal it History logs every Break it and Heal it change. For pasted records with an unknown critical tag, Heal it removes that record. ### Take it further For a live name, the certificate the name serves now to the SSL Certificate Checker, where the issuer can be compared with the policy; the registrable domain to the Subdomain Finder, which lists every name in its certificates; and the zone that holds the records to the DNSSEC Checker, since CAs are asked to validate CAA with DNSSEC. ## Method ### 1. Finding the relevant records The server asks Cloudflare for CAA records at the name; the resolver follows aliases, as the RFC asks. If the name exists but has none, the page asks the parent, then its parent, and stops at the first name that has some. [RFC 8659 section 3](https://www.rfc-editor.org/rfc/rfc8659#section-3): "The search for a CAA RRset climbs the DNS name tree from the specified label up to, but not including, the DNS root "." until a CAA RRset is found." Records found at a parent are shown as inherited. ### 2. Reading each record Each record is flags, tag and value ([RFC 8659 section 4.1.1](https://www.rfc-editor.org/rfc/rfc8659#section-4.1.1)). Bit 0 of the flags (value 128) is the issuer critical flag. Known tags are `issue`, `issuewild`, `iodef`, `issuemail` ([RFC 9495](https://www.rfc-editor.org/rfc/rfc9495)), `contactemail` and `contactphone`. The CA identifier is the value up to the first `;`; parameters after it are kept but not evaluated. Identifiers are named from a catalog of 16 (Let's Encrypt, Google Trust Services, Amazon, Sectigo and Comodo, DigiCert, GlobalSign, GoDaddy, ZeroSSL, SSL.com, Buypass, Entrust, HARICA, Certum). ### 3. The policy - **Ordinary certificates**: the CAs named by `issue` records; any CA when there are none. - **Wildcard certificates**: the CAs named by `issuewild` records when there are any, otherwise the `issue` rule. [RFC 8659 section 4.3](https://www.rfc-editor.org/rfc/rfc8659#section-4.3): "If at least one issuewild Property is specified in the Relevant RRset for a Wildcard Domain Name, each issue Property MUST be ignored when processing a request for that Wildcard Domain Name." - **Refusals reported to**: the `iodef` values ([section 4.4](https://www.rfc-editor.org/rfc/rfc8659#section-4.4)). ### 4. Rules - **No CAA records** (info): any CA may issue. The default for most of the web, not an error. - **Critical flag on an unknown tag** (fail). [RFC 8659 section 4.1](https://www.rfc-editor.org/rfc/rfc8659#section-4.1): "A CA MUST NOT issue certificates for any FQDN if the Relevant RRset for that FQDN contains a CAA critical Property for an unknown or unsupported Property Tag." A tag this tool does not know may be one a CA does not know either. - **No CA may issue ordinary certificates** (info): an `issue` record with no CA, such as `0 issue ";"`. [Section 4.2](https://www.rfc-editor.org/rfc/rfc8659#section-4.2): owners "can use an issue Property Tag with no issuer-domain-name to request no issuance." - **identifier is not a known CA identifier** (info): the value is not in the catalog. It may still be valid. - **No iodef contact** (info): CAs that refuse a request have nowhere to report it. - **Ordinary certificate issuance is unrestricted** (info): records exist, but none of them is an `issue` record. - **Issuance is limited** (pass): N CAs may issue ordinary certificates. ### 5. Comparing with the certificate logs For a looked-up name, the server searches crt.sh for certificates under the registrable domain. Only entries for exactly this name, or the wildcard covering it, are kept, and only when the name still has at least one valid certificate; every issuer the logs show for such an entry is counted, including issuers of its earlier certificates, and named from the same catalog. Each issuer that the policy would refuse for that kind of certificate gives a check, "CA issued certificates here but is not allowed" (or "issued wildcard certificates"). It is a check, not a failure: the certificate may predate the record, or come from a service issuing on your behalf, and its next renewal with that CA will be refused. When the search does not answer (crt.sh limits its rate and is sometimes down), an info finding says "Certificate logs not checked", and the verdict says so, so a missing comparison is never read as a clean one. When the public suffix data needed to find the registrable domain cannot load, a check says "Certificate comparison not checked". ## Standards and conformance | Specification | Sections used | How the tool applies it | Where it stops | | --- | --- | --- | --- | | [RFC 8659](https://www.rfc-editor.org/rfc/rfc8659) | [3](https://www.rfc-editor.org/rfc/rfc8659#section-3), [4.1](https://www.rfc-editor.org/rfc/rfc8659#section-4.1), [4.1.1](https://www.rfc-editor.org/rfc/rfc8659#section-4.1.1), [4.2](https://www.rfc-editor.org/rfc/rfc8659#section-4.2), [4.3](https://www.rfc-editor.org/rfc/rfc8659#section-4.3), [4.4](https://www.rfc-editor.org/rfc/rfc8659#section-4.4), [5.1](https://www.rfc-editor.org/rfc/rfc8659#section-5.1) | Tree climbing, the critical flag, issue, issuewild precedence and iodef as specified | The climb stops below the top-level domain, where the RFC includes it; TLDs rarely publish CAA. Obsoletes [RFC 6844](https://www.rfc-editor.org/rfc/rfc6844) | | [RFC 8657](https://www.rfc-editor.org/rfc/rfc8657) | | `accounturi` and `validationmethods` parameters are shown in the value | Not evaluated: a policy that limits an account still reads as "may issue" | | [RFC 9495](https://www.rfc-editor.org/rfc/rfc9495) | | `issuemail` is a known tag and explained | S/MIME issuance is not summarised | | [CA/Browser Forum Baseline Requirements](https://cabforum.org/working-groups/server/baseline-requirements/documents/) | 3.2.2.8, CAA records processing | The reason every public CA checks CAA | The tool does not model CA-specific exceptions | [RFC 8659 section 5.1](https://www.rfc-editor.org/rfc/rfc8659#section-5.1): "The use of DNSSEC to authenticate CAA RRs is strongly RECOMMENDED but not required." The tool does not validate the records it reads; the DNSSEC Checker reads the zone's chain. ## Finding reference ### Policy findings | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | Issuance is limited | pass | [RFC 8659 4.2](https://www.rfc-editor.org/rfc/rfc8659#section-4.2) | Only the named CAs may issue | Add a CA before you switch to it | | Critical flag on an unknown tag | fail | [RFC 8659 4.1](https://www.rfc-editor.org/rfc/rfc8659#section-4.1) | Every CA that does not know the tag refuses to issue | Set the flag to 0, or remove the record | | CA issued certificates here but is not allowed | check | [RFC 8659 3](https://www.rfc-editor.org/rfc/rfc8659#section-3) | The current policy does not authorize that observed issuer for the certificate type | Allow the CA, or move that service to an allowed CA | ### Incomplete and informational evidence | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | Certificate comparison not checked | check | | The apex could not be computed; logs were not searched | Reload | | No CAA records | info | [RFC 8659 3](https://www.rfc-editor.org/rfc/rfc8659#section-3) | Any CA may issue | Publish issue records for the CAs you use | | No CA may issue ordinary certificates | info | [RFC 8659 4.2](https://www.rfc-editor.org/rfc/rfc8659#section-4.2) | Every ordinary request is refused | Replace with an issue record if the name needs certificates | | identifier is not a known CA identifier | info | [RFC 8659 4.2](https://www.rfc-editor.org/rfc/rfc8659#section-4.2) | Possibly a typo, possibly a CA the catalog lacks | Check the CA's documentation | | No iodef contact | info | [RFC 8659 4.4](https://www.rfc-editor.org/rfc/rfc8659#section-4.4) | No reporting destination is published; reporting is not guaranteed even with iodef | Add `0 iodef "mailto:…"` | | Ordinary certificate issuance is unrestricted | info | [RFC 8659 3](https://www.rfc-editor.org/rfc/rfc8659#section-3) | Records exist but none restricts issue | Add issue records | | Certificate logs not checked | info | | The comparison was not made | Look the name up again later | | The name does not exist | fail | [RFC 2308 2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1) | No name to issue for | Check the name | | The resolver could not answer | fail | [RFC 1035 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) | CAs that see this failure may refuse to issue | Check the DNSSEC chain | ## Guide ### Write a policy 1. List every service that gets certificates for your names: your web host or CDN, your mail host, a status page, a help desk. The [SSL Certificate Checker](https://tamperbox.dev/ssl-checker) shows the issuer of what each serves; the [Subdomain Finder](https://tamperbox.dev/subdomain-finder) lists the names in your certificates. 2. Publish one `issue` record per CA at the registrable domain: `example.com. 3600 IN CAA 0 issue "letsencrypt.org"`. 3. Add `issuewild` only if wildcard certificates come from a different CA, and `0 iodef "mailto:security@example.com"` for reports. 4. Look a deep subdomain up here to confirm it inherits the policy, and check that no logged issuer is flagged. Confirm from a terminal: `dig +short CAA example.com` lists `flags tag "value"` lines; `dig +short CAA www.example.com` returns nothing when the name inherits. ### A renewal was refused Look the exact name up here. If the CA that refused is not in the policy, add it; if the policy is inherited from a parent you do not control, publish records at the name itself, which then take precedence. If a critical tag is flagged, set its flag to 0. ### Changing CA Add the new CA's `issue` record first, issue with it, and only then remove the old one. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | Inherited from the parent | `shop.harbor-supply.example` | The parent's records, marked inherited | | No CAA records | a sample domain with none | "Any certificate authority may issue" | | Critical unknown tag | your records plus `128 tbs "unknown"` | The critical-tag failure, and Heal it removing it | | Nobody may issue | `0 issue ";"` at your name | "No CA may issue ordinary certificates" | ## Worked example `harbor-supply.example` publishes four records: `0 issue "letsencrypt.org"`, `0 issue "sectigo.com"`, `0 issuewild "sectigo.com"` and `0 iodef "mailto:security@harbor-supply.example"`. Ordinary certificates may come from Let's Encrypt or Sectigo, wildcard certificates from Sectigo only, and refusals are reported by mail. The sample's certificate-log data shows current certificates for this name from Sectigo and Let's Encrypt, both allowed, so the verdict reads "Let's Encrypt and Sectigo may issue for harbor-supply.example." with that comparison under it, and Findings carries one pass. Other certificates in the sample logs, for subdomains, are not counted against this name. Press "Inherited from the parent" to see `shop.harbor-supply.example` governed by these records, and "Critical unknown tag" to see the one mistake that blocks every CA. ## For agents The Tamperbox MCP server exposes `caa_lookup` with a `name`. Unlike this page, the operation reads the CAA records at the name itself: parent-domain inheritance is not evaluated, so call it again for each parent when the name has none. It returns an `evidence` object containing the question, status, flags, answer and authority, plus `records` for the requested type. Keep these warnings with any conclusion: - Authorization does not prove that a certificate was issued or is trusted. - CAs check CAA only at issuance; existing certificates are unaffected. - One answer from one resolver at one moment. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/). The operation also returns `policy`, `checks` and an explicit exact-name scope. It does not perform the page’s certificate-log comparison. ## Limits - The climb stops below the top-level domain. - Account and validation-method parameters are not evaluated. - The certificate-log search can miss recent or private certificates, and can be unavailable. - A logged issuer outside the policy is not proof of mis-issuance. - Pasted records are read as text, with no climbing and no log search. - Sample names under `.example` are answered in the browser. ## References - [RFC 8659](https://www.rfc-editor.org/rfc/rfc8659): DNS Certification Authority Authorization (CAA) resource record. Sections 3, 4.1, 4.1.1, 4.2, 4.3, 4.4, 5.1. Obsoletes [RFC 6844](https://www.rfc-editor.org/rfc/rfc6844). - [RFC 8657](https://www.rfc-editor.org/rfc/rfc8657): CAA record extensions for account URI and ACME method binding. - [RFC 9495](https://www.rfc-editor.org/rfc/rfc9495): CAA processing for email addresses. - [CA/Browser Forum Baseline Requirements](https://cabforum.org/working-groups/server/baseline-requirements/documents/): section 3.2.2.8, CAA records processing. - [crt.sh](https://crt.sh/): the certificate-log search the comparison uses. - [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308) section 2.1 and [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035) section 4.1.1, for the failure states. --- # CDN Detector How Tamperbox combines DNS, network and HTTPS response clues to identify a likely content delivery network. Canonical: https://docs.tamperbox.dev/tools/cdn-detector/ Updated: 2026-10-25 Applies to: tamperbox.dev, October 2026 Prerequisites: a website hostname or pasted response evidence Outputs: CNAME, address-network and header signals, their agreement, redirects and possible origin leakage Limitations: Public observations are time-sensitive and do not prove ownership, intent or private configuration The tool page is [tamperbox.dev/cdn-detector](https://tamperbox.dev/cdn-detector). It opens with a live lookup of `mozilla.org`; replace it to inspect your own target. This guide documents the actual input path, evidence contract, classifications and independent verification steps. <div class="tb-callout"><strong>Where processing happens:</strong> input cleanup, pasted-data parsing and report rendering happen in the browser. Live checks send only the validated public target to the Tamperbox server and the public services required for the lookup. The page stores no report; History is local to the current browser session.</div> ## What the tool answers The checker answers whether several independent public signals suggest a CDN and whether those signals agree about the provider. Its conclusion is deliberately narrower than an ownership or security claim. A displayed provider, product, name or passing check means that the listed public evidence matched a documented rule at the observation time. Every conclusion is paired with evidence. The opening verdict is a summary for orientation, while Findings contains the actionable interpretation and the later result sections retain the underlying records, addresses, fields or names. If a conclusion matters operationally, verify that evidence through an authoritative account or an independent standards-aware client before changing production. ## Inputs ### Accepted source Enter a domain for live DNS, network-owner and HTTPS checks, or paste HTTP response headers for local classification. Pasted headers provide only HTTP evidence; they cannot establish a CNAME chain or address owner. The parser retains response status and header fields. A live HTTPS failure leaves the DNS and network evidence available with a limitation. Text files are read in the browser. The resulting input follows the same classification rules as the field; reading a file locally does not make a domain or public-IP lookup offline. Cleanup keeps an already accepted record intact and otherwise tries unwrapping a single-line address. Unusable text remains visible for correction. ### When work runs Domain input runs after a 600-millisecond typing pause. Enter runs it immediately; pasted records run immediately. Drops and page-wide paste use the same input loader. Leaving the field applies cleanup and reruns only when cleanup changes the text. Each edit aborts the previous request and increments a generation marker. A slower old response therefore cannot replace a newer result, and clearing the source immediately clears copyable output. The opening input uses the same parser and processing path as a replacement. The labelled live default sends the same requests as another domain. ## Reading the result ### Verdict and privacy The verdict states what the available evidence supports and uses pass, check, fail or informational status consistently. Pass means the bounded rule succeeded. Check means a human should confirm context. Fail means a concrete operational rule was violated. Info describes a limitation, absence or neutral fact and must not be promoted into success or failure by an automated reader. Two privacy lines distinguish browser-only work from live lookup work. The Checked line names the cleaned input and source mode. Copy result is hidden while work is pending, after an error and when input is empty, preventing a stale report from being exported as current. ### Findings and evidence Findings are ordered with failures first, then checks, informational notes and passes. Repeated passing details can fold into a disclosure so that exceptions remain visible. Each item states the observation and its consequence; any remediation is scoped to the evidence rather than presented as a universal configuration recipe. Evidence sections follow Findings and precede History. They are the audit trail for the verdict. A provider label derived from a catalog remains an inference, while a literal record or response field remains an observation. This distinction matters when signatures are incomplete, white-labelled or stale. ### History and handoffs History records intentional input replacements, including Break it examples and their repairs. Revert restores the prior input and runs it again, including live requests when applicable; Reset input returns to the value at the beginning of the recorded sequence. History is not monitoring, persistence or an account log. Check the rest carries the current input to other tools in Domains & hosting. Take it further sends an observed address to [ASN Lookup](https://docs.tamperbox.dev/tools/asn-lookup/) and a different redirect destination to the [Website Hosting Checker](https://docs.tamperbox.dev/tools/website-hosting/) or [Website Technology Detector](https://docs.tamperbox.dev/tools/website-technology/). The redirect destination is a separate target: the original host’s signals do not describe it. Each receiving tool runs its own check; agreement is not guaranteed. Explicit tool links transfer the input through temporary browser `sessionStorage` and, when needed, a same-origin browser channel. The URL fragment contains a random transfer token, not the input. Transfers are accepted for less than one minute, consumed once, and bound to the destination path. The destination removes the token from its address. Ordinary documentation links and direct visits do not restore a previous input; if transfer storage is unavailable, the link still opens the tool. ## Method ### Validation and collection Before collection, the same domain validation runs in the browser and on the server boundary. Requests are restricted to supported public DNS names and HTTPS roots, redirects are bounded, response sizes are capped and abort signals are propagated. These limits make the observation reproducible and prevent an entered value from becoming an unrestricted network fetch. Use the input modes above to determine which requests run. DNS evidence comes from a public recursive view and can reflect cache state. Local classification cannot add observations absent from the supplied evidence. A server lookup is a fresh observation, not confirmation that cached or pasted evidence is still current. ### Classification rules The checker resolves the host, maps returned addresses, fetches the HTTPS root and scores catalogued signatures in CNAME suffixes, network ownership and response fields. It keeps each signal visible. [RFC 9110 section 3.7](https://www.rfc-editor.org/rfc/rfc9110#section-3.7) distinguishes origins, proxies and gateways, so a header alone is never treated as conclusive. A redirect is reported because the entered host and final host can have different delivery paths. No confidence percentage is invented. When sources disagree, the disagreement is a finding. When a source is unavailable, the affected conclusion becomes informational or inconclusive rather than silently using a previous result. Catalog matches are exact bounded rules; unknown is a valid outcome. ### Ordering and export The renderer calculates all findings from the current observation before updating the verdict, chips, evidence and landing cards. Status priority is fail, check, info, pass. Stable secondary ordering keeps repeated runs readable without changing severity. The Markdown mirror and Copy result output preserve input, summary, findings and important evidence in text form. They do not embed secrets, browser state or the expanded educational cards. Agents should cite the observation time and limitation alongside any exported conclusion. ## Standards and conformance ### Applied specifications | Source | Rule used | Boundary | | --- | --- | --- | | [RFC 1034 section 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2) | DNS aliases expose a canonical chain | The chain is evidence, not proof of traffic handling | | [RFC 9110 section 5](https://www.rfc-editor.org/rfc/rfc9110#section-5) | HTTP fields carry extensible metadata | Known response signatures are matched case-insensitively | | [RFC 9110 section 7.6.3](https://www.rfc-editor.org/rfc/rfc9110#section-7.6.3) | Via identifies intermediaries in a forwarding chain | Absence of Via does not mean absence of a CDN | | [RFC 9111 section 1](https://www.rfc-editor.org/rfc/rfc9111#section-1) | HTTP caching may be performed by intermediaries | Cache behavior itself is not benchmarked | These references define the records and message semantics, not the provider catalogs. A catalog is product logic and can lag branding, acquisitions or custom deployments. Where a standard permits several valid configurations, the tool reports the observed form and avoids declaring one commercial pattern universally correct. ### Where conformance stops The checker is an observer, not an authoritative DNS server, browser, certificate monitor, mail receiver or provider control plane. It does not claim protocol conformance for the target. It applies selected validation and interpretation rules to bounded evidence and exposes the boundary where a fuller protocol operation would begin. The phrase “public” refers to the server's Internet view. Private split-horizon answers, authenticated dashboards and regional routing can differ. Cached answers can remain until TTL expiry, and HTTP intermediaries can transform what the origin sent. ## Finding reference ### Emitted findings | Finding | Severity | Meaning | Repair or next check | | --- | --- | --- | --- | | Signals agree | Pass | Available CNAME, network and header clues name one CDN | Confirm in the provider account for operational decisions | | Signals disagree | Check | At least one available clue names another path | Inspect redirects, multi-CDN routing and stale DNS | | Origin shows through | Info | A response field names software behind the edge | Strip unnecessary origin-identifying fields at the CDN | | Signals for another CDN | Info | A second provider has multiple clues | Check layered or migrating delivery | | Site was not fetched | Info | DNS evidence exists but HTTPS failed | Retry and test the response directly | | No CDN signature | Info | The bounded catalog found no match | Treat as unknown, not proof of direct hosting | | Redirects to another host | Info | Visitors finish on a different name | Inspect the destination separately | Wording can include the observed name, count, provider or status. Automated consumers should use the supplied status and evidence rather than parsing the English title as a permanent identifier. A missing finding is not evidence that the corresponding external condition is absent when its source could not be collected. ### Status handling | Status | Consumer action | What not to infer | | --- | --- | --- | | Pass | Preserve the evidence and continue normal review | Permanent correctness, ownership or availability | | Check | Confirm intent and inspect the named evidence | Definite compromise or outage | | Fail | Prioritise the concrete broken rule and verify independently | That every user sees the same failure | | Info | Carry the limitation or neutral fact with the report | Success merely because no failure was emitted | ## Guide ### Verify independently Start with an authoritative or widely used command-line client. For DNS, use `dig` with the exact record type and compare every returned owner, target and TTL. Add `+trace` only when delegation matters; a trace and a recursive answer solve different questions. For HTTPS, use `curl -I --location https://host/` and retain each hop and response field. For certificates, use an established TLS client and a CT monitor you trust. Repeat from another network when geography or split routing could matter. Save the observation time and the original evidence before editing. After a DNS change, wait at least the prior TTL and then query both the intended authorities and independent recursive resolvers. ### Repair safely Do not delete an unfamiliar record or reroute a public name merely because a catalog labels it. First identify the owning service, deployment repository or provider account. Confirm whether the item is current, a migration remnant, a failover path or a delegated responsibility. Make the smallest reversible change, keep the prior value, and have a rollback trigger. Re-run this page after propagation, then verify the user-visible service. A clean public lookup cannot prove application health. Conversely, an informational unknown does not require a speculative change. ### Diagnose conflicting evidence When two signals disagree, ask whether they describe different layers: apex versus www, resolver cache versus authority, CDN edge versus origin, entered host versus redirected host, or certificate history versus current DNS. Compare literal evidence before comparing labels. The disagreement itself often reveals a migration or intermediary. If a lookup fails, preserve the error and retry once. Repeated timeouts are not equivalent to empty data. Use the specialist tool linked by the finding for deeper parsing rather than converting an inconclusive aggregate result into a failure. ### Break it and heal it Break it can remove matching CDN and cache headers from the current pasted or captured response without inventing replacement headers. A remaining status line is still valid input. This teaches the limits of signature detection; it does not disable a CDN. The bare-domain action is available only for a current www hostname. Missing signatures do not prove a direct connection to an origin, and software headers do not prove the origin’s address. The Break it controls create documented edge cases from the visitor's own input or a reserved fixture. They are teaching states, not scans. Heal it restores a safe derived value when the repair is deterministic. Revert remains available when several changes have been made. Use these cases to learn how invalid, missing, mixed or stale evidence appears before diagnosing production. The control never edits DNS, hosting, certificates or provider accounts. ## Worked example The live default is `mozilla.org`. Its response and network evidence demonstrate why the tool exposes disagreement rather than forcing a confident provider label. Live routing may change, so the documentation records the method rather than freezing the result. Read the example from verdict to Findings, then compare the literal evidence. Open one Break it case and use Heal it or Revert. Finally, replace the default with a domain you are authorised to assess. This sequence demonstrates both the successful path and the failure contract without implying that the named public domain endorses the tool. ## For agents Agents can discover the `cdn_detector` operation through Tamperbox MCP. The browser page id `cdn-detector` is not the operation name. The server operation and browser renderer can expose different fields; inspect the operation schema before supplying arguments. Preserve the result's distinction between observed evidence, catalog inference and limitation. State whether the run was live or pasted, include the cleaned target and observation time, and never turn “not found” into “does not exist” unless the method truly establishes that condition. Choose a specialist operation when the task is narrow. Use this page's report when its combined view or educational findings add value. Do not pass credentials, private hostnames or customer data into a public lookup. If a repair would change production, present the exact evidence, expected effect, propagation window and rollback before acting. Machine readers should branch on status and structured fields where available, not English punctuation. Treat network and parse errors as inconclusive. Re-run after a meaningful interval rather than repeatedly polling a third-party source. ## Limits A CDN can hide or rewrite every catalogued clue, while an origin can imitate a familiar header. Geo steering and split DNS can return different providers elsewhere. The HTTPS request is one server-side vantage point and does not measure cache hits, latency, shielding, WAF behavior or contractual ownership. All outputs are point-in-time observations. Resolver caching, negative caching, anycast, geo steering, redirects and intermittent upstream failures can change a later run. The service does not retain a monitoring history or notify on change. Local History is an interaction aid, not durable evidence. No result grants permission to probe a target or modify it. Use authorised accounts and owner-approved procedures for deeper checks. Where business, security or legal decisions depend on attribution, obtain confirmation from the responsible provider or domain operator. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034), Domain Names — Concepts and Facilities, especially [section 4.3.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.3.2) for resolver behavior. - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035), Domain Names — Implementation and Specification, especially [section 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1) for resource-record types and classes. - [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110), HTTP Semantics, especially [section 3.7](https://www.rfc-editor.org/rfc/rfc9110#section-3.7) for intermediaries and [section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) for status codes when HTTP evidence is collected. - [Tamperbox CDN Detector](https://tamperbox.dev/cdn-detector), the interactive tool and current Markdown mirror. --- # CNAME Lookup How the CNAME Lookup follows an alias chain to the name that holds the address, what a dangling alias, an apex CNAME, a loop and a long chain mean, every rule it applies, and how to fix and confirm each one. Canonical: https://docs.tamperbox.dev/tools/cname-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A DNS name, or CNAME records to paste Outputs: A verdict for the chain, findings, the chain drawn from the name to its end with each step's TTL, the addresses the end holds, and the answer as dig-style text Limitations: The chain is followed by asking for A records, so the end's AAAA records are not checked; a dangling alias is reported but whether someone can claim the target is not tested The tool page is [tamperbox.dev/cname-lookup](https://tamperbox.dev/cname-lookup). It opens on `status.harbor-supply.example`, a sample name on the reserved `.example` zone whose status page sits behind three aliases. This page is the long version: how the chain is followed, every rule applied to it, and how to fix a dangling or misplaced alias. <div class="tb-callout"><strong>Where processing happens:</strong> a name is sent to the Tamperbox server, which asks Cloudflare for its A records over DNS over HTTPS; the resolver follows every CNAME and returns each step. Pasted records are read in your browser and never uploaded. The public suffix list used for the apex check is loaded into the page. Sample names under <code>.example</code> are answered in the browser. Ordinary lookup results are not persisted by this page. An explicit handoff temporarily stores its value in session storage for one-use transfer.</div> ## What the tool answers A CNAME record makes one name an alias for another, its canonical name ([RFC 1034 section 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2)). A resolver that meets one restarts the question at the target, and keeps going until it reaches a name with real records. The tool answers: 1. **Is this name an alias, and of what?** Each step from the name to the end of the chain. 2. **Does the end exist?** An alias to a name that is gone is dangling, the setup behind subdomain takeovers. 3. **Is the alias in a place DNS forbids?** A CNAME cannot share its name with other records, so it cannot sit at a zone's apex. 4. **Does the chain loop or run long?** Loops never resolve; long chains are slow and fragile. 5. **What does the end hold?** The IPv4 addresses the resolver returned with the chain. An alias is not an HTTP redirect: the browser keeps showing your name, and the server at the end must accept requests for it. The [Redirect Checker](https://tamperbox.dev/redirect-checker) traces HTTP redirects. ## Inputs ### A name `www.example.com`, `status.example.com`. The lookup runs when you stop typing, or on Enter. The name is validated in the browser and on the server. A pasted address or email address is reduced to its host, and the hint names what was kept; text that does not reduce stays as pasted. ### Pasted records Anything with a space or a quote is read as records, in the browser: dig answers, zone file lines, or a bare target per line. The chain is drawn from the records in the order they link. Whether the end exists cannot be known for pasted records, so a dangling alias is never reported for them. ### Files Drop a `.txt` file anywhere on the page. ## Reading the result ### Verdict and chips "Alias: www.example.com points to example.net." for one step, "3 aliases to edge.example.net." for a chain, "Dangling alias: target does not exist." or "No CNAME record at name." when the name holds its own records. The chip counts the steps or says Dangling. ### Where your input goes Pasted records stay in the browser; a name means one DNS query from our server. ### Findings Failures and checks, worst first, or one pass naming the chain. ### CNAME records The chain as a path: the name, each target with the TTL of the step that leads to it, and the end, marked when it does not exist. Under it, what the end holds. ### DNS response The answer as dig-style text, with a copy button. ### History and Heal it History logs Break it and Heal it replacements. Revert restores the previous input; Reset input restores the first input in that sequence. Restoring a live name runs a fresh lookup. Typing starts a new history, and the log is not a monitoring record. ### Take it further The end of the chain to the DNS Lookup (every record it holds), its first address to the ASN Lookup, and, for a live name, the end to the hosting check, or for a dangling alias the target's registrable domain to the availability check. ## Method ### 1. Following the chain The server asks Cloudflare for the name's A records, not its CNAME. A recursive resolver that meets a CNAME "simply restarts the query at the new name" ([RFC 1034 section 5.2.2](https://www.rfc-editor.org/rfc/rfc1034#section-5.2.2)) and returns every CNAME it passed through in the answer section, followed by the A records of the end. Asking for A therefore yields the whole chain in one query. The CNAME records in the answer are the steps; any other records are what the end holds. A name that is not an alias returns its own A records and no CNAME: "No CNAME record at name", info. ### 2. Rule: the end must exist When the answer carries CNAME steps but the status is NXDOMAIN, the last target does not exist: fail, "target does not exist", and the verdict "Dangling alias". [RFC 1034 section 5.2.2](https://www.rfc-editor.org/rfc/rfc1034#section-5.2.2) says resolvers should catch "aliases which point to non-existent names". The harm is what happens next: if the target was a name at a hosting provider (a bucket, a blog, a status page, an app), whoever registers that name at the provider can serve content on your name, and pages there can read cookies scoped to your parent domain. ### 3. Rule: no CNAME at the apex [RFC 1034 section 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2): "If a CNAME RR is present at a node, no other data should be present." [RFC 2181 section 10.1](https://www.rfc-editor.org/rfc/rfc2181#section-10.1) restates it: a name has one CNAME and nothing else, or other records and no CNAME. The top of every zone must hold its SOA and NS records ([RFC 1034 section 4.2.1](https://www.rfc-editor.org/rfc/rfc1034#section-4.2.1)), so a CNAME there contradicts the zone itself. When the first owner in the chain equals its registrable domain under the public suffix list, the finding is fail, "CNAME at the zone apex". Wildcard owners, including a bare `*`, are never treated as the apex. ### 4. Rule: no loops When a target leads back to a name already in the chain: fail, "CNAME loop". [RFC 1034 section 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2): "CNAME chains should be followed and CNAME loops signalled as an error." ### 5. Check: more than two aliases Three or more steps: check, "N aliases in a row". [RFC 1034 section 5.2.2](https://www.rfc-editor.org/rfc/rfc1034#section-5.2.2) asks that multiple levels of aliases "be avoided due to their lack of efficiency, but should not be signalled as an error", so it is a check, not a failure. Each step is another lookup for a resolver that has not cached it. ### 6. When the suffix data cannot load The apex rule needs the public suffix list, which is loaded on demand. If it fails, the chain is still drawn and a check, "Apex check unavailable", says the owner was not compared with a registrable domain. ### 7. Verdict A dangling end sets the verdict; otherwise the first failure; otherwise "Alias:" for one step or "N aliases" for more, as pass, or as check when only the chain-length finding applies. ## Standards and conformance | Specification | Sections used | How the tool applies it | Where it stops | | --- | --- | --- | --- | | [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034) | [3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2), [4.2.1](https://www.rfc-editor.org/rfc/rfc1034#section-4.2.1), [5.2.2](https://www.rfc-editor.org/rfc/rfc1034#section-5.2.2) | Loops and dangling ends are failures; long chains are a check; the apex rule follows from 3.6.2 and 4.2.1 | The chain is followed by the resolver; the tool does not ask each step itself | | [RFC 2181](https://www.rfc-editor.org/rfc/rfc2181) | [10.1](https://www.rfc-editor.org/rfc/rfc2181#section-10.1) | One CNAME per name and no other data beside it | DNSSEC records beside a CNAME are allowed and not reported | | [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308) | [2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1) | NXDOMAIN after CNAME steps means the last target does not exist | | | [Public Suffix List](https://publicsuffix.org/list/) | | The apex is approximated by the registrable domain | A zone delegated below the registrable domain (`shop.example.com` as its own zone) has an apex the tool does not detect | ## Finding reference | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | One alias / N aliases | pass | [RFC 1034 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2) | The name resolves through the chain | None | | target does not exist | fail | [RFC 1034 5.2.2](https://www.rfc-editor.org/rfc/rfc1034#section-5.2.2) | Visitors get an error; whoever claims the target can serve content on your name | Remove the CNAME, or recreate the target | | CNAME at the zone apex | fail | [RFC 1034 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2), [RFC 2181 10.1](https://www.rfc-editor.org/rfc/rfc2181#section-10.1) | Mail and other records at the apex break; resolvers answer inconsistently | Use an ALIAS, ANAME or flattened record, or A and AAAA | | CNAME loop | fail | [RFC 1034 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2) | The name never resolves | Point the last alias outside the loop | | N aliases in a row | check | [RFC 1034 5.2.2](https://www.rfc-editor.org/rfc/rfc1034#section-5.2.2) | Slower first lookups; more parties that can break it | Point the first name at the end | | Apex check unavailable | check | | The apex rule was skipped | Reload to retry | | No CNAME record at name | info | [RFC 2181 10.1](https://www.rfc-editor.org/rfc/rfc2181#section-10.1) | The name holds its own records | None | | The name does not exist | fail | [RFC 2308 2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1) | No record of any kind at the name | Check the name | | The resolver could not answer | fail | [RFC 1035 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) | Validating resolvers return nothing | Check the DNSSEC chain | ## Guide ### Close a dangling alias 1. Decide whether you still need the name. If not, delete the CNAME at your DNS provider. That closes the risk at once. 2. If you need it, recreate the target at the provider it belonged to (the same bucket or app name), or point the alias somewhere you control. 3. Look the name up here: the chain should end in addresses, or the name should no longer be an alias. 4. Find the others. List every CNAME in your zone and look each one up; aliases to services you cancelled are the usual suspects. Confirm from a terminal: `dig +short CNAME old-blog.example.com` shows the target, and `dig old-blog.example.com A` shows `status: NXDOMAIN` while it dangles. ### Point a bare domain at a host The apex cannot be a CNAME. Most DNS providers offer a record that behaves like one: ALIAS, ANAME, or CNAME flattening. The provider looks up the target itself and answers with addresses, so the apex keeps its SOA, NS and MX records. If yours does not, publish the A and AAAA records the host gives you. Keep `www` as a CNAME. ### Shorten a chain Find the steps you own: an alias from `www` to `web` to the provider's name can usually point straight at the provider's name. Keep any step the provider asks for, since it may move its own names behind it. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | Dangling alias | a sample alias to a deleted blog host | The dangling-alias failure and its cards | | CNAME at the apex | your registrable domain as a pasted CNAME | "CNAME at the zone apex" | | Not an alias | your registrable domain | "No CNAME record", the normal state of most names | | Name does not exist | `nohost.` in front of your name | NXDOMAIN | ## Worked example `status.harbor-supply.example` is an alias for `harbor-supply.status.example`, which is an alias for `eu.edge.status.example`, which is an alias for `eu-lb-3.edge.status.example`, which holds the address `192.0.2.61`. The verdict reads "3 aliases to eu-lb-3.edge.status.example." with "The sample zone followed the chain." under it. Findings carries one check, "3 aliases in a row": the chain works, but a resolver with an empty cache makes four lookups before it has an address. The cards suggest pointing the name at the status provider's name directly. Take it further hands the end of the chain to the DNS Lookup and its address to the ASN Lookup; both answer the sample in the browser. Press Dangling alias and the page looks up `old-blog.harbor-supply.example`, an alias for a blog host that no longer exists: the verdict turns to "Dangling alias", and the cards explain the takeover risk and how to close it. ## For agents The Tamperbox MCP server exposes `cname_lookup` with a `name`. Unlike this page, the operation asks for the CNAME record at the name itself; it does not traverse the full alias chain and does not judge whether a dangling target can be claimed. To follow a chain, call `dns_lookup` with type A: the answer section lists every step. Keep these warnings with any conclusion: - A dangling alias is a finding, not proof of takeover: exploitability depends on the provider. - The end's AAAA records are not part of an A query. - One answer from one resolver at one moment. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/). ## Limits - The chain is followed by one A query; AAAA at the end is not checked. - The apex is approximated by the registrable domain from the public suffix list. - Pasted records cannot show a dangling end. - One answer from one resolver at one moment. - Sample names under `.example` are answered in the browser. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034): sections 3.6.2 (aliases and canonical names), 4.2.1 (zone top), 5.2.2 (resolver handling of aliases). - [RFC 2181](https://www.rfc-editor.org/rfc/rfc2181): section 10.1, CNAME records. Updates RFC 1034 and RFC 1035. - [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308): section 2.1, NXDOMAIN. - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035): section 4.1.1, response codes. - [Public Suffix List](https://publicsuffix.org/list/): registrable domains. --- # Code mode Discover operation schemas, execute allowlisted requests, and return only the evidence a task needs. Canonical: https://docs.tamperbox.dev/mcp/code-mode/ Updated: 2026-10-19 Applies to: MCP 0.2.0 Prerequisites: A connected Tamperbox MCP server Outputs: Focused schema fragments or composed operation results Limitations: Each execution has time, memory, result-size, and API-call budgets. ## Search before execution Filter `operations` by the task language and return the operation ID, method, path, descriptions, and schemas you need. ```js return operations .filter((op) => /spf|dmarc|dkim/i.test(`${op.summary} ${op.description}`)) .map((op) => ({ operationId: op.operationId, method: op.method, path: op.path, inputSchema: op.inputSchema, outputSchema: op.outputSchema, })); ``` Avoid returning the full OpenAPI document. Focused discovery keeps context small and reduces schema mistakes. ## Execute documented calls Use the uppercase HTTP method and exact path returned by discovery. Put path parameters in the path, scalar query values in `query`, and JSON input in `body`. ```js const formatted = await tamperbox.request({ method: 'POST', path: '/v1/tools/json_format', body: { input: { mediaType: 'application/json', value: '{"ready":true}' }, options: { indent: 2 }, }, }); return formatted.output; ``` ## Preserve interpretation Return warnings and provenance when they affect the conclusion. A DNS failure is not an empty answer. A decoded token is not verified. A server-side HTTP observation is not a complete security audit. ## Compose carefully Feed one operation's artifact into another only when the output and input schemas match. Await every request. Outstanding requests are cancelled when the execution ends. --- # Connect an MCP client Configure Tamperbox MCP through local stdio or the public Streamable HTTP endpoint. Canonical: https://docs.tamperbox.dev/mcp/connect/ Updated: 2026-10-19 Applies to: MCP 0.2.0 Prerequisites: An MCP-compatible client; Node.js 22 or later for stdio Outputs: A connected Tamperbox server exposing search and execute Limitations: Exact configuration keys vary by client. ## Local stdio Use the published npm package when the client can launch a local process. ```json { "mcpServers": { "tamperbox": { "command": "npx", "args": ["-y", "tamperbox-mcp@0.2.0"] } } } ``` Restart or reload the client after changing its MCP configuration. A successful connection exposes exactly two tools, `search` and `execute`. ## Public HTTP endpoint Use the hosted endpoint when the client supports Streamable HTTP: ```text https://mcp.tamperbox.dev/mcp ``` The public endpoint does not require an API key. Inputs sent through it pass through the model provider and the hosted MCP service before an API request is made. ## Confirm the connection Ask the client to list the Tamperbox tools or to inspect one operation schema without running a check. If discovery succeeds, ask for a synthetic `json_format` example and confirm that the result reports one attempted API call. Client-specific examples live in the [Tamperbox MCP repository](https://github.com/oceanrescue/tamperbox-mcp/tree/main/examples). --- # Contributing Improve the public Tamperbox documentation with focused changes and verifiable product claims. Canonical: https://docs.tamperbox.dev/contributing/ Updated: 2026-10-19 Applies to: Documentation base 0.1.0 Prerequisites: Node.js 22 or later; Git Outputs: A checked documentation change ready for review Limitations: Product claims must stay aligned with versioned Tamperbox source and schemas. ## Local setup ```sh git clone https://github.com/oceanrescue/tamperbox-doc.git cd tamperbox-doc npm ci npm run dev ``` ## Content contract Every page includes a review date, product version, agent summary, prerequisites, outputs, and limitations. These fields support the visible docs and the generated agent resources. Add user-facing pages under `src/content/docs`. Update `astro.config.mjs` when the page belongs in the primary sidebar. ## Verify changes ```sh npm run check npm run build ``` The static build must include the human-readable page, its `.md` mirror, `llms.txt`, `llms-full.txt`, and the sitemap. ## Claim discipline Check product claims against the [Tamperbox MCP repository](https://github.com/oceanrescue/tamperbox-mcp), its bundled OpenAPI document, and current release records. Separate implemented behavior from proposals and future work. --- # CORS Tester What the CORS Tester sends from the Tamperbox server, how it replays the browser's CORS algorithm on the preflight and the actual response, what each step means, and how to fix and verify each block. Canonical: https://docs.tamperbox.dev/tools/cors-tester/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: The URL a page calls, the origin of that page, the method and request header names it uses, or response headers copied from a browser's network panel Outputs: A verdict of Allowed, Blocked or Not decided, the browser's checks in order with what was sent beside what came back, the headers that would allow the request in six server syntaxes, and the raw exchange Limitations: The Tamperbox server is not your users' browser; requests that could change data are never sent; no cookies or header values travel; a pasted block is judged in the role you give it The tool page is [tamperbox.dev/cors-tester](https://tamperbox.dev/cors-tester). It opens with `https://tamperbox.dev/` in the box and nothing sent; you name the calling page's origin and press Send preflight. This page is the long version: what the server sends, every step the tool replays from the browser's algorithm, what each outcome means, and how to fix and verify each one. <div class="tb-callout"><strong>Where processing happens:</strong> pressing Send preflight sends the URL, origin, method and header names to the Tamperbox server, which sends one OPTIONS request and, for GET and HEAD only, one request carrying just the Origin header, then returns the status and headers of each. Pasted response headers are read in your browser and never uploaded. No cookies, no header values and no request bodies are ever sent. Nothing is stored.</div> ## What the tool answers Four questions, in the order a browser asks them: 1. **Does this request need a preflight?** A method or header outside the safelist makes the browser ask first. 2. **Did the preflight permit it?** A 2xx status, the origin allowed, credentials allowed when cookies are sent, the method and every custom header listed. 3. **Can the page read the real response?** The origin and credentials rules again, on the response to the actual request. 4. **Will caches keep it that way?** `Vary: Origin` when a specific origin is echoed, and how long the preflight is cached. The verdict names one of three outcomes. **Blocked** names the step that failed. **Allowed** means every step passed and an actual response was checked. **Not decided** means nothing failed but the exchange is incomplete: the real request was not sent because the method could change data, or a pasted exchange lacks one of its two halves. ## Inputs ### A URL to call The box takes the address the page would call. `parseUrl` in `site-ui.js` reads it: an address without a scheme gets `https://`; spaces, non-HTTP schemes, a user name or password, a port other than 80 or 443, an IP address and a host without a top-level domain are refused with a message, and the port and credential cases offer a repair. The fragment is dropped. Pasted text is tidied by the shared cleaner (`cleanInput` in `lib/input-clean.js`, applied through `tidySource`): a quoted or bracketed address loses its wrapping and trailing punctuation, and the hint says what was kept. Because this is a page tool, the whole address stays, not just the host. Text that fits nothing stays as pasted so the parser's message explains it. Typing is never rewritten; a break or repair load is never cleaned. A real server is never contacted on its own. The page shows "Ready to test" and waits for Enter or the Send preflight button. The reserved `harbor-supply.example` hosts answer from a local fixture at once, without a network request. ### The request below the box | Field | What the tool does with it | | --- | --- | | Calling page origin | Must be a scheme and host, optionally a port, with no path, query or trailing slash; `null` is accepted as the opaque origin. Sent as `Origin`. | | Method | GET, HEAD, POST, PUT, PATCH or DELETE. Sent as `Access-Control-Request-Method`. Only GET and HEAD are ever sent as the actual request. | | Request headers | Names only, split on commas or whitespace, lowercased, deduplicated and sorted; at most 20 valid token names. Sent as `Access-Control-Request-Headers`. Values are never asked for. | | Send cookies | A flag that switches on the credentials rules. No cookie is ever sent. | | Single pasted response is | Preflight or Actual, used only when one pasted block is supplied. | Changing the origin or headers re-checks pasted headers and fixture endpoints at once; a real server waits for Enter or the button again. When the box holds a real address, the fixture's origin `https://www.harbor-supply.example` is cleared, so a third party's server is never probed with the sample origin. ### Pasted response headers Text that starts with a status line or `name: value` lines is read as responses by `parseResponses` in `http-checks.js`: each `HTTP/x 2xx` line starts a block, header names are lowercased, and an indented continuation line joins the header above it. One block is judged in the role you select, with an assumed status of 204 for a preflight and 200 for an actual response when no status line was pasted. Two blocks are the preflight first and the actual response second. Nothing in a paste leaves the browser. ## Reading the result ### Verdict and chips The verdict line is Blocked, Allowed or Not decided, followed by the failing step's title or a sentence naming the origin, host and request. The chips are buttons: "Blocked at step n", "Preflight needed" or "No preflight", and "n checks passed", each scrolling to the steps. ### Findings Findings repeat the steps that failed or warned, worst first; passes fold into one line. ### What the browser checks One row per step, in the order the browser applies them, each with a badge and, where it applies, "Browser sends" beside "Server answers" with the exact header lines. After a block, a greyed row says what never happens: the request is not sent, or the page cannot read the response. After a passing preflight for a method the tool does not send, a greyed row says the request itself was not sent. ### Headers that would allow it When a step blocks the request, the code window holds the response headers that would allow it, built by `corsFix` from what the server already sent, in the syntax of the server you pick: nginx, Apache, Caddy, a `_headers` file, IIS `web.config` or Express. The note under it says where the lines go and whether they belong on the OPTIONS answer or on the actual response. ### Requests and responses The raw exchange: for a live check, the OPTIONS request and the GET or HEAD request as our server sent them, with each answer's status, time and headers, the CORS headers marked. For a paste, the blocks as pasted. ### History Break it and Heal it log what they replaced. Revert undoes the newest change and Reset input returns to what you entered, including the request fields a break changed. ### Take it further Take it further carries a value derived from this result into another tool in the same category: the Redirect Checker at the request URL when the preflight was redirected, the preflight as a curl command into the Postman Collection Converter, and the HTTP/3 and Compression Checker at the API origin. Each opens the other tool with the value in its box; nothing is put in a URL. ## Method The evaluation is `evaluateCors` in `public/lib/http-checks.js`, run in the browser on the preflight and actual responses, whether they came from our server or from a paste. It stops at the first failure, as a browser does. ### Step 1: is a preflight needed? A request is sent directly when its method is GET, HEAD or POST and every request header is one of `accept`, `accept-language` or `content-language`. Anything else triggers a preflight. This is stricter than the [Fetch Standard's CORS-safelisted request-header](https://fetch.spec.whatwg.org/#cors-safelisted-request-header) rule, which also safelists `Content-Type` with the values `application/x-www-form-urlencoded`, `multipart/form-data` and `text/plain`, and `Range` with a simple range. The tool asks for header names only, never values, so it cannot tell a form body from a JSON body and treats `Content-Type` as custom; a JSON body is the usual case, and the stricter reading shows the preflight such a request will trigger. The [CORS-safelisted method](https://fetch.spec.whatwg.org/#cors-safelisted-method) list is applied as the standard writes it. ### Step 2: the preflight status A preflight must get a 2xx status. In the [CORS-preflight fetch](https://fetch.spec.whatwg.org/#cors-preflight-fetch) the standard says: "If response's status is not an ok status, then return a network error." The tool reports three failures: | Outcome | Finding | Rule | | --- | --- | --- | | No response | Preflight got no answer | The OPTIONS request failed at DNS, connect or timeout; the stage is named | | 3xx or any `Location` | Preflight was redirected (status) | Fetch sets the preflight's redirect mode to `error`, so a redirect is a network error | | Other non-2xx | Preflight answered (status) | An ok status is 200 to 299; 404 and 405 are the common framework answers | Our server sends the OPTIONS with `redirect: manual`, so a redirect is seen, not followed, and the `Location` is shown. ### Step 3: the origin The [CORS check](https://fetch.spec.whatwg.org/#cors-check) decides this step, on the preflight and again on the actual response. The standard: "If origin is null, then return failure", "If origin is `*` and credentials mode is not include, then return success", "If request's origin, serialized and UTF-8 encoded, is not origin, then return failure", "If credentials mode is not include, then return success", "If allowCredentials is not `true`, then return failure". The tool's readings, in order: no header is a block; more than one header or a comma-separated value is a block (the header holds exactly one origin or `*`); `*` with cookies is a block; `*` without cookies passes; any other value must equal the calling origin byte for byte, as [RFC 6454 section 7](https://www.rfc-editor.org/rfc/rfc6454#section-7) serializes an origin, which has no trailing slash. ### Step 4: credentials Only with Send cookies on. `Access-Control-Allow-Credentials` must be exactly `true`, lowercase; anything else, including a missing header, is a block. ### Step 5: method and headers Checked on the preflight only, and only for the parts that made it necessary. The method must appear in `Access-Control-Allow-Methods` exactly as written, or the list must contain `*` and the request must be without credentials. Each custom header must appear in `Access-Control-Allow-Headers`, compared case-insensitively, or `*` must be present without credentials; `*` never covers `Authorization`, which must be named. Both follow the wildcard rules in the [CORS-preflight fetch](https://fetch.spec.whatwg.org/#cors-preflight-fetch): "If request's credentials mode is not include and methods contains `*`" and the matching sentence for headers, with the `Authorization` exception stated there. ### Step 6: caching the preflight `Access-Control-Max-Age` is information, never a block. Without it the tool says browsers cache the answer for 5 seconds, the default the standard sets for a [max-age value](https://fetch.spec.whatwg.org/#http-access-control-max-age) that is absent; Chrome caps any value at 7,200 seconds, a browser limit, not a standard one. ### Step 7: the actual response Our server sends the actual request only for GET and HEAD, and only when no preflight was needed or the preflight permitted the request as judged by the same rules on the server. It carries the `Origin` header and nothing else that identifies you. A status below 400 passes; 4xx and 5xx are noted, not failed, because CORS can allow a page to read an error. The origin and credentials rules run again. Then, when a specific origin is echoed without `Vary: Origin` ([RFC 9110 section 12.5.5](https://www.rfc-editor.org/rfc/rfc9110#section-12.5.5)), a warning says a shared cache can serve one origin's answer to another, as [RFC 9111 section 4.1](https://www.rfc-editor.org/rfc/rfc9111#section-4.1) describes the use of `Vary` in selecting a stored response. `Access-Control-Expose-Headers` is listed as information. The result is Allowed only when no step failed, the preflight was present whenever it was needed, and an actual response was checked. POST, PUT, PATCH and DELETE are never sent because they could change data on a server you may not own, so a passing preflight for them ends in Not decided. ## Standards and conformance The tool is an observer of one exchange, not a conforming user agent. It reproduces the browser's decision procedure on the responses it has and names where it is stricter or stops. ### Fetch Standard, CORS protocol The [CORS protocol](https://fetch.spec.whatwg.org/#http-cors-protocol) of the WHATWG Fetch Living Standard is the current specification; the W3C Cross-Origin Resource Sharing Recommendation of 2014 is obsolete and superseded by it, and is cited here only as history. Implemented in the browser from the responses: the preflight ok-status and redirect rules, the CORS check, the wildcard rules for methods and headers with the `Authorization` exception, and the max-age default. Implemented on our server: the decision to send the actual request only after a preflight that passes the same rules. Stricter than the standard: `Content-Type` and `Range` always count as custom headers, because the tool knows names, not values. Not implemented: the `Access-Control-Allow-Private-Network` check, the CORS-safelisted response-header filtering beyond listing `Access-Control-Expose-Headers`, and the preflight cache itself. ### RFC 6454, the Web Origin Concept [RFC 6454](https://www.rfc-editor.org/rfc/rfc6454) is a Proposed Standard. Section 7 defines the serialization the tool compares against: scheme, host and port, no path. The page refuses an origin with a path, query or trailing slash before anything is sent, and accepts the string `null` as the opaque origin. ### RFC 9110 and RFC 9111 [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110), HTTP Semantics, is an Internet Standard that replaces the earlier RFC 7230 family of HTTP semantics documents. Used: [section 9.3.7](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.7) for OPTIONS, [section 15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4) for the 3xx class the tool treats as a redirect on a preflight, and [section 12.5.5](https://www.rfc-editor.org/rfc/rfc9110#section-12.5.5) for `Vary`. [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111), HTTP Caching, [section 4.1](https://www.rfc-editor.org/rfc/rfc9111#section-4.1), is behind the `Vary: Origin` warning, which is a cache-compatibility warning, not evidence that any cache misbehaved. ## Finding reference Each row is a step the code can emit, with its id in `evaluateCors`. Ids beginning with `preflight-` and `actual-` are the same rule applied to each response. ### Blocks at the preflight | Finding | Id | Severity | Standard | Meaning for the page | Fix | | --- | --- | --- | --- | --- | --- | | Preflight got no answer | preflight-status | Fail | Fetch, CORS-preflight fetch | The OPTIONS never got a response from this vantage point | Check DNS, the firewall and that OPTIONS reaches the application | | Preflight was redirected (status) | preflight-status | Fail | Fetch, redirect mode error | The browser stops; the request is never sent | Answer OPTIONS at the requested URL itself, before any redirect rule | | Preflight answered (status) | preflight-status | Fail | Fetch, ok status | Usually no route handles OPTIONS, or auth middleware rejected it | Route OPTIONS to a handler that answers 204 before authentication | | Preflight allows no origin | preflight-origin | Fail | Fetch, CORS check | No `Access-Control-Allow-Origin` | Send the calling origin or `*` | | More than one allowed origin | preflight-origin | Fail | Fetch, CORS check | A list is not a valid value | Echo the one origin that asked, with `Vary: Origin` | | Wildcard origin with credentials | preflight-origin | Fail | Fetch, CORS check | `*` is refused when cookies are sent | Echo the exact origin and send `Access-Control-Allow-Credentials: true` | | Origin (x) is not the one allowed | preflight-origin | Fail | RFC 6454 section 7 | The server allows a different origin, or the same one with a slash | Match scheme, host and port exactly | | Credentials not allowed | preflight-credentials | Fail | Fetch, CORS check | With cookies, `true` is required | Send `Access-Control-Allow-Credentials: true` | | (Method) not allowed | methods | Fail | Fetch, preflight wildcard rule | Method missing from the list, or `*` with credentials | List the method by name; names are case-sensitive | | (Header) not allowed | headers | Fail | Fetch, preflight wildcard rule | Header missing, or `Authorization` under `*` | Add each name to `Access-Control-Allow-Headers` | ### Blocks and warnings at the actual response | Finding | Id | Severity | Standard | Meaning for the page | Fix | | --- | --- | --- | --- | --- | --- | | Request got no answer | actual-status | Fail | None | The GET or HEAD failed from this vantage point | Check reachability; a preflight alone cannot allow the call | | Response (status) | actual-status | Pass or Info | None | Below 400 passes; an error is still readable if CORS allows it | None for CORS; fix the application error separately | | Response allows no origin, More than one, Wildcard with credentials, Origin not the one allowed | actual-origin | Fail | Fetch, CORS check | The same origin rules, on the response the page reads | Send the origin headers on the actual response too, not only on OPTIONS | | Credentials not allowed | actual-credentials | Fail | Fetch, CORS check | Same as the preflight rule | Same as above | | No Vary: Origin | vary | Check | RFC 9110 section 12.5.5, RFC 9111 section 4.1 | A shared cache can hand one origin's answer to another | Add `Vary: Origin` whenever a specific origin is echoed | ### Information rows | Finding | Id | Severity | Meaning | | --- | --- | --- | --- | | Preflight required | needed | Info | Names the method or headers that make the browser ask first | | No preflight needed | needed | Info | A simple request; the response alone decides | | Preflight not supplied | preflight-missing | Info | A paste without the OPTIONS block; the actual response is still checked | | Preflight cached for n s, Preflight not cached | max-age | Info | How long browsers reuse the answer; 5 seconds without the header | | Extra headers readable | expose | Info | The headers `Access-Control-Expose-Headers` lets the page read | | Any origin allowed (*) | preflight-origin, actual-origin | Pass | Fine for public data; cookies would need the exact origin | ## Guide ### The preflight answers 404 or 405 The framework has no route for OPTIONS, or an authentication layer runs before the CORS handler and rejects a request that carries no token. Browsers never send credentials with a preflight, so the handler must answer before authentication. Route OPTIONS to a handler that returns 204 with the allow headers. The tool's code window gives the lines for your server; for nginx it is one `add_header … always;` line per header in the server block, where `always` keeps the headers on error responses too. Confirm independently: ``` curl -i -X OPTIONS 'https://api.example.com/v1/items' \ -H 'Origin: https://app.example.com' \ -H 'Access-Control-Request-Method: PUT' \ -H 'Access-Control-Request-Headers: content-type' ``` The status line must be 2xx and the `Access-Control-Allow-*` lines must be present. Then press Send preflight again. ### The preflight is redirected A rule that adds `https://`, a trailing slash or `www` runs before CORS, or a sign-in redirect catches OPTIONS. The browser treats any redirect on a preflight as a network error. Make the page call the final address, and make OPTIONS answer at that address without a redirect. Take it further hands the request URL to the Redirect Checker so you can see the chain the preflight hit. ### Wildcard origin with cookies `Access-Control-Allow-Origin: *` is refused the moment the request carries credentials. Echo the requesting origin, add `Access-Control-Allow-Credentials: true`, and add `Vary: Origin`. Decide first whether the endpoint needs cookies at all; a bearer token in a header is a custom header, not credentials, and works with `*` only if `Authorization` is named in `Access-Control-Allow-Headers`. ### A header is missing from Allow-Headers The commonest block. The server lists `Content-Type` but the page also sends `Authorization` or `X-Request-Id`. Add every name the page sends; `*` covers all of them only without credentials and never covers `Authorization`. The code window merges what the server already sends with what the request needs, so pasting it does not drop existing names. ### The origin is echoed without Vary: Origin Not a block today, but a CDN or shared proxy may cache the response for one origin and serve it to another, which then fails the origin check. Add `Vary: Origin` wherever a specific origin is echoed. ### Break it and Heal it | Break it | What it loads | What it shows | | --- | --- | --- | | Send cookies | `open.harbor-supply.example` with credentials on | Wildcard origin with credentials | | Another origin | Origin `https://other-site.example` | Origin not the one allowed | | PUT with JSON | PUT with `Content-Type` | PUT not allowed on an endpoint that lists GET and POST | | OPTIONS not handled | `legacy-api.harbor-supply.example`, PUT with `Content-Type` | Preflight answered 405 | | Preflight redirected | `moved-api.harbor-supply.example` | Preflight was redirected (301) | | No preflight needed | GET with no headers | A simple request judged on its response alone | Breaks that change only the request keep your own URL when you entered one; the two fixture-only cases load the reserved host. A break never probes a real server with the fixture's origin. For a pasted exchange that is blocked, Heal it offers "Add the headers that allow it": it adds the proposed headers to each pasted block in its own role, keeps the status codes, and checks again. Method, header and max-age permissions go on the preflight; origin and credentials go on both. ## Worked example The page opens with `https://tamperbox.dev/` loaded and the sample origin cleared, so nothing is sent until you enter the origin of your own page and press Send preflight. Live evidence changes, so this page does not record what that server answers; read the steps as they come back. The reserved fixture `https://api.harbor-supply.example/v1/stock` with origin `https://www.harbor-supply.example`, GET and the `Authorization` header, is synthetic sample data answered locally. Its policy allows the shop's own origins with credentials, lists GET and POST, allows only `Content-Type` and caches the preflight for 600 seconds. Read end to end: step 1, a preflight is required because of `Authorization`; step 2, the preflight answers 204; step 3, the origin matches exactly; step 4, Authorization not allowed, Blocked, and the greyed row says the GET is never sent. The code window proposes `Access-Control-Allow-Origin: https://www.harbor-supply.example`, `Access-Control-Allow-Headers: Content-Type, Authorization`, `Vary: Origin` and `Access-Control-Max-Age: 600`. ## For agents The Tamperbox MCP server exposes two MCP tools: use `search` to inspect the catalog and schema, then use `execute` to call `POST /v1/tools/cors_tester` through `tamperbox.request`. Supply `url` and `origin`; optionally set `method`, `headers` (up to 20 unique header names) and `credentials`. The `credentials` flag only switches on the credentials rules; no cookie is sent. The result carries the preflight and actual responses with their status, headers and timing, and `actualSkipped` says why no actual request was sent (`method` or `preflight_failed`), plus warnings and provenance. Keep these warnings with any conclusion: - The exchange was observed from the Tamperbox server, not from a user's browser. A server can answer differently by address, cookie or firewall. - POST, PUT, PATCH and DELETE are never sent; a passing preflight for them is Not decided. - `Content-Type` is treated as a custom header; a real form body might not trigger a preflight. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the URL and origin travel. ## Limits - Our server is one client in one place. Address-based rules, geographic rules, cookies and firewalls can make a browser's exchange differ from this one. - Only OPTIONS and, when permitted, GET or HEAD are sent. No request body, no cookie, no header value, at most 20 header names. - Header names are known; values are not. `Content-Type` therefore always counts as custom. - A pasted block is judged in the role you give it; the tool does not infer whether headers came from OPTIONS or from the real request. - Allowed needs a checked actual response. A preflight alone is never Allowed. - The preflight cache and private-network access checks are not modelled. - Nothing is stored. ## References - [Fetch Living Standard, CORS protocol](https://fetch.spec.whatwg.org/#http-cors-protocol). WHATWG, continuously updated; the current specification of CORS. Sections used: [CORS-safelisted method](https://fetch.spec.whatwg.org/#cors-safelisted-method), [CORS-safelisted request-header](https://fetch.spec.whatwg.org/#cors-safelisted-request-header), [CORS-preflight fetch](https://fetch.spec.whatwg.org/#cors-preflight-fetch), [CORS check](https://fetch.spec.whatwg.org/#cors-check) and [Access-Control-Max-Age](https://fetch.spec.whatwg.org/#http-access-control-max-age). Supersedes the W3C Cross-Origin Resource Sharing Recommendation of January 2014, which is obsolete. - [RFC 6454, The Web Origin Concept](https://www.rfc-editor.org/rfc/rfc6454). Proposed Standard, December 2011. Section used: [7](https://www.rfc-editor.org/rfc/rfc6454#section-7), serialization of an origin. - [RFC 9110, HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110). Internet Standard, June 2022; replaces the earlier HTTP semantics documents, including [RFC 2818](https://www.rfc-editor.org/rfc/rfc2818) and [RFC 7230](https://www.rfc-editor.org/rfc/rfc7230). Sections used: [9.3.7](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.7), [12.5.5](https://www.rfc-editor.org/rfc/rfc9110#section-12.5.5) and [15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4). - [RFC 9111, HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111). Internet Standard, June 2022; obsoletes [RFC 7234](https://www.rfc-editor.org/rfc/rfc7234). Section used: [4.1](https://www.rfc-editor.org/rfc/rfc9111#section-4.1). --- # DANE & TLSA Checker How the checker finds the servers behind a domain, reads their TLSA records through a validating resolver, compares each record with the certificate chain the server presents, every rule it applies, what each finding means for mail in transit, and how to fix and verify each one. Canonical: https://docs.tamperbox.dev/tools/dane-checker/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain, a host:port on a supported TLS port, or a TLSA record to paste Outputs: A verdict with one chip per server, findings with fixes, a card per server showing each TLSA record and what it matched, and the record's three fields in words Limitations: One observation from one location; DNSSEC is taken from the resolver's AD flag, not validated independently; a match is association evidence, not a complete DANE certification-path validation; DANE-TA name checks and certificate dates are not evaluated The tool page is [tamperbox.dev/dane-checker](https://tamperbox.dev/dane-checker). It opens on a live check of the mail servers of `tamperbox.dev`; replace that domain to inspect your own. This page is the long version: how the servers are found, every rule the tool applies to their TLSA records, what each finding means for mail in transit, and how to fix and verify each one. <div class="tb-callout"><strong>Where processing happens:</strong> a domain or host is sent to the Tamperbox server, which asks a public validating resolver for the MX and TLSA records and opens one TLS connection to each server that publishes TLSA records (STARTTLS on ports 25 and 587). A pasted TLSA record is parsed in your browser and never uploaded. Nothing is stored.</div> ## What the tool answers DANE for SMTP ([RFC 7672](https://www.rfc-editor.org/rfc/rfc7672)) lets a domain publish, in DNSSEC-signed DNS, which certificate or key each of its mail servers will present. A sending server that supports DANE then requires TLS to that server and refuses an impostor, which closes the STARTTLS downgrade that plain opportunistic TLS leaves open. The tool answers, per server: 1. **Which servers are checked?** The MX hosts of a domain in preference order, the domain itself on port 443, or one host:port. 2. **Does the server publish TLSA records?** The records at `_port._tcp.host`. 3. **Are they protected by DNSSEC?** Whether the resolver's answer carried the Authenticated Data (AD) flag. 4. **Do they match the server?** Each record compared with the leaf certificate or the issuing certificates the server sent. 5. **Is the record type a good choice for mail?** PKIX usages on port 25 are flagged. ## Inputs ### A domain `example.com`. When you stop typing, or on Enter, the server resolves the MX records. With **Mail servers (MX, port 25)** selected, every exchanger is checked on port 25, lowest preference first. With **Web server (port 443)**, the domain itself is checked on port 443. A domain with no MX record, or a null MX (`0 .`, [RFC 7505](https://www.rfc-editor.org/rfc/rfc7505#section-3)), reads "No mail servers", and Heal it offers the web server instead. ### A host and port `mx1.example.net:25`. Exactly one server is checked; the service selector is hidden. The probe accepts the ports in the table below and refuses the rest with "Choose a supported TLS service port." | Port | How the probe connects | | --- | --- | | 25, 587 | Plain SMTP, then STARTTLS ([RFC 3207](https://www.rfc-editor.org/rfc/rfc3207#section-4)) | | 443, 465, 853, 993, 995 | TLS from the first byte | ### A pasted record `3 1 1 2b5f…`, with or without its owner name, class and TTL (`_25._tcp.mx1.example.net. 300 IN TLSA 3 1 1 …`). Text that contains `TLSA` or starts with three small numbers and hex is treated as a record and explained in the browser with no lookup. ### What the page does to your input | You paste | The box keeps | | --- | --- | | `https://example.com/blog` | `example.com` | | `postmaster@example.com` or `mailto:postmaster@example.com` | `example.com` | | `"example.com"`, `<example.com>` | `example.com` | | A TLSA record | the record, unchanged | | Text that fits nothing | the text as pasted, with the error | Typing is never rewritten, and Break it cases are loaded exactly as written. ## Reading the result ### Verdict and chips The verdict names the outcome across all servers and the first server in trouble; one chip per server carries its state. Copy result copies the verdict, findings and server cards as text. ### Findings Problems come first, worst first. Two or more passes fold into one "n checks passed" line; open it to see each server that matched. ### History Break it, Heal it and a change of the service selector are logged. Revert undoes the newest change; Reset input returns to what you entered. ### Take it further Links that carry a server from this result into another security tool: the certificate and STARTTLS of the primary server, of the server that failed or could not be compared (or the last-preference server when all is well), and for a web server its post-quantum key exchange and security headers. They appear only for live lookups. ### Servers One card per server: host and port, its state (Matches, No match, No TLSA, No DNSSEC, Not connected), MX preference, each TLSA record with its parameters in words and what it matched ("Matches the server certificate", "Matches the issuing CA", "Matches nothing the server presented", "Not compared"), whether the answer was DNSSEC-validated, the TLS version, and the leaf's subject, issuer and expiry date. ### What the record says The first readable record's usage, selector and matching type, each in words, and the length of its data. ## Method The rules run in this order. Code: `public/dane-checker.js` and `parseTlsa`, `tlsaMatches` in `public/lib/dns-intel.js`. ### Finding the servers For a domain in mail mode, the MX RRset is read and sorted by preference, as a sending server would ([RFC 7672 section 2.2.1](https://www.rfc-editor.org/rfc/rfc7672#section-2.2.1)). The TLSA owner name for each server is `_<port>._tcp.<host>` ([RFC 6698 section 3](https://www.rfc-editor.org/rfc/rfc6698#section-3); [RFC 7672 section 2.2.3](https://www.rfc-editor.org/rfc/rfc7672#section-2.2.3)). For mail, the records belong under the MX host names, not under your domain, so a provider's shared MX hosts carry the provider's records. ### Reading the TLSA answer The query goes to a public validating resolver. A response code other than NOERROR or NXDOMAIN stops the check with "TLSA lookup returned …; no DANE conclusion can be drawn", because RFC 7672 treats a lookup error differently from absence: lookup errors "MUST result in falling back to the next SMTP server or delayed delivery" ([section 2.2](https://www.rfc-editor.org/rfc/rfc7672#section-2.2)). ### Parsing each record Usage must be 0 to 3, selector 0 or 1, matching type 0 to 2, and the data hexadecimal ([RFC 6698 section 2.1](https://www.rfc-editor.org/rfc/rfc6698#section-2.1)); anything else is "A TLSA record is usage (0–3), selector (0–1), matching type (0–2) and hex data". A SHA-256 association must be 64 hex characters and a SHA-512 one 128 ([section 2.1.3](https://www.rfc-editor.org/rfc/rfc6698#section-2.1.3)); otherwise the record is unreadable. ### DNSSEC protection The tool takes the AD flag of the resolver's answer as the DNSSEC verdict. Records without it are "No DNSSEC": RFC 7672 says an "insecure" TLSA RRset means the client "SHOULD be made using (pre-DANE) opportunistic TLS" ([section 2.2](https://www.rfc-editor.org/rfc/rfc7672#section-2.2)), so the records do nothing. ### Comparing with the server When a server publishes records, the probe connects and returns, for every certificate in the chain, the full DER and SHA-256 and SHA-512 digests of both the certificate and its public key. The selector picks certificate or key, the matching type picks full data or a digest ([RFC 6698 section 2.1.2](https://www.rfc-editor.org/rfc/rfc6698#section-2.1.2)). | Usage | Compared with | Extra condition | | --- | --- | --- | | 3 DANE-EE | the leaf only | none ([RFC 7671 section 5.1](https://www.rfc-editor.org/rfc/rfc7671#section-5.1)) | | 2 DANE-TA | the certificates after the leaf | none ([RFC 7671 section 5.2](https://www.rfc-editor.org/rfc/rfc7671#section-5.2)) | | 1 PKIX-EE | the leaf only | the probe's ordinary CA validation must pass | | 0 PKIX-TA | the certificates after the leaf | the probe's ordinary CA validation must pass | ### Deciding a server's state | Order | Condition | State | | --- | --- | --- | | 1 | No TLSA records | No TLSA | | 2 | Records, no AD flag | No DNSSEC | | 3 | Any record matches | Matches | | 4 | The chain was read, nothing matches | No match | | 5 | The probe could not connect | Not connected | One matching record is enough: RFC 7672 requires the client to authenticate the server against the usable records, and a set passes when any one of them matches ([section 3.2](https://www.rfc-editor.org/rfc/rfc7672#section-3.2)). For a set with usable records, a failure "MUST result in falling back to the next SMTP server or delayed delivery" ([section 2.2](https://www.rfc-editor.org/rfc/rfc7672#section-2.2)), which is why a No match is a fail. ### The verdict across servers "No DANE" when no server publishes TLSA; "No match" or "n of m pass DANE" naming the first failing host; "Not protected" when records lack DNSSEC; "n of m pass" with the uncompared host when some matched and some could not be reached; "Not compared" when none could be reached; otherwise a pass, downgraded to a warning when some servers have no TLSA. ### Usage advice for port 25 A record with usage 0 or 1 on a mail server is an info finding. RFC 7672: "TLSA records for the port 25 SMTP service used by client MTAs SHOULD NOT include TLSA RRs with certificate usage PKIX-TA(0) or PKIX-EE(1)" ([section 3.1.3](https://www.rfc-editor.org/rfc/rfc7672#section-3.1.3)). ## Standards and conformance ### RFC 6698, the TLSA record Implemented: the record format and the three parameters ([section 2.1](https://www.rfc-editor.org/rfc/rfc6698#section-2.1)), the owner name ([section 3](https://www.rfc-editor.org/rfc/rfc6698#section-3)), selector and matching computations, evaluated against the chain the probe returns. Stops at: the tool does not build a certification path from a trust anchor that the server did not send. Status: Proposed Standard, updated by [RFC 7218](https://www.rfc-editor.org/rfc/rfc7218) (the acronyms the page shows) and [RFC 7671](https://www.rfc-editor.org/rfc/rfc7671). ### RFC 7671, DANE operations Implemented: DANE-EE matches the leaf alone, regardless of names ([section 5.1](https://www.rfc-editor.org/rfc/rfc7671#section-5.1)); DANE-TA matches a certificate the server presents above the leaf ([section 5.2.2](https://www.rfc-editor.org/rfc/rfc7671#section-5.2.2)). The guide follows its rollover procedure ([section 8.1](https://www.rfc-editor.org/rfc/rfc7671#section-8.1)). Differs: the tool does not apply DANE-TA path constraints, and does not flag matching type Full(0), which [section 5.2.1](https://www.rfc-editor.org/rfc/rfc7671#section-5.2.1) marks NOT RECOMMENDED. ### RFC 7672, SMTP security via opportunistic DANE TLS Implemented: MX order ([section 2.2.1](https://www.rfc-editor.org/rfc/rfc7672#section-2.2.1)), `_25._tcp` lookup ([section 2.2.3](https://www.rfc-editor.org/rfc/rfc7672#section-2.2.3)), secure versus insecure and error handling ([section 2.2](https://www.rfc-editor.org/rfc/rfc7672#section-2.2)), the PKIX usage advice ([section 3.1.3](https://www.rfc-editor.org/rfc/rfc7672#section-3.1.3)). Stops at: CNAME expansion of the TLSA base domain is left to the resolver, so the candidate pair of [section 2.2.3](https://www.rfc-editor.org/rfc/rfc7672#section-2.2.3) is not tried separately; DANE-TA name checks ([section 3.2.2](https://www.rfc-editor.org/rfc/rfc7672#section-3.2.2)) are not evaluated; a secure set whose records are all unusable is not distinguished from one that does not match. ### DNSSEC [RFC 9364](https://www.rfc-editor.org/rfc/rfc9364) (BCP 237) is the current DNSSEC reference. The tool relies on the resolver's AD flag ([RFC 4035 section 3.2.3](https://www.rfc-editor.org/rfc/rfc4035#section-3.2.3)) and does not validate signatures itself. For the zone's own chain of trust, use the DNSSEC Checker. ## Finding reference ### Failures | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | `<host>: no record matches` | fail | [RFC 7672 §2.2](https://www.rfc-editor.org/rfc/rfc7672#section-2.2) | DANE senders refuse to deliver to this server and queue the mail | Publish the record for the presented key, keep the old one two TTLs, then remove it | | `<host>: unreadable record` | fail | [RFC 6698 §2.1](https://www.rfc-editor.org/rfc/rfc6698#section-2.1) | The record cannot match anything | Recompute the data; no colons or spaces; 64 or 128 hex characters | | `Wrong data length` (pasted) | fail | [RFC 6698 §2.1.3](https://www.rfc-editor.org/rfc/rfc6698#section-2.1.3) | The digest is truncated or too long | Copy the full digest again | ### Warnings | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | `<host>: TLSA without DNSSEC` | warn | [RFC 7672 §2.2](https://www.rfc-editor.org/rfc/rfc7672#section-2.2) | Senders ignore the records | Sign the zone and publish its DS at the registrar | ### Information and passes | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | `<host>: certificate not compared` | info | none | The probe could not complete a handshake; no conclusion | Retry; confirm STARTTLS or TLS is reachable from the internet | | `<host>: usage 0/1 on a mail server` | info | [RFC 7672 §3.1.3](https://www.rfc-editor.org/rfc/rfc7672#section-3.1.3) | Senders treat PKIX usages as unusable for SMTP | Publish 3 1 1 or 2 0 1 instead | | `No TLSA record at …` / `No TLSA records on any server` | info | [RFC 7672 §2.2](https://www.rfc-editor.org/rfc/rfc7672#section-2.2) | Opportunistic TLS only | Deploy DNSSEC, then TLSA | | `n servers without TLSA` | info | [RFC 7672 §2.2](https://www.rfc-editor.org/rfc/rfc7672#section-2.2) | Mail to those servers is not protected | Cover every MX host, or remove it | | `No mail servers for <domain>` | info | [RFC 7505 §3](https://www.rfc-editor.org/rfc/rfc7505#section-3) | Nothing to check for mail | Check the web server, or publish MX | | `<host>: record matches` | pass | [RFC 7672 §3.2](https://www.rfc-editor.org/rfc/rfc7672#section-3.2) | One record names the presented key or its issuer | None | ## Guide ### A server fails after a certificate renewal 1. Compute the record for the key the server presents now: `openssl s_client -connect mx1.example.net:25 -starttls smtp </dev/null 2>/dev/null | openssl x509 -noout -pubkey | openssl pkey -pubin -outform DER | openssl dgst -sha256`. The digest is the data of a `3 1 1` record. 2. Publish it at `_25._tcp.mx1.example.net` next to the old record. 3. Wait at least two TTLs of the TLSA RRset, then remove the old record ([RFC 7671 section 8.1](https://www.rfc-editor.org/rfc/rfc7671#section-8.1)). 4. Next time, publish the next key's record before you switch, or reuse the key on renewal. ### Records without DNSSEC Sign the zone that holds the MX host at its DNS provider and publish the DS at the registrar. Confirm with `dig +dnssec TLSA _25._tcp.mx1.example.net`: the `ad` flag must appear in the header. ### Confirm a match yourself `dig +short TLSA _25._tcp.mx1.example.net` lists the records; the openssl pipeline above gives the 3 1 1 digest to compare. For a 2 0 1 record, take the issuing certificate from `openssl s_client -showcerts` and hash its DER. ### Break it and Heal it | Break it | What it shows | Heal it | | --- | --- | --- | | Web server | Your host on port 443, usually No DANE | Restore input before this break | | One server | Your first mail server alone | Restore input before this break | | Truncated record | A 3 1 1 record with 4 hex characters | Restore input before this break | | No mail servers | A domain with no MX | Check the web server instead | ## Worked example The page opens on a live check of `tamperbox.dev`. Its MX hosts are a mail provider's shared servers, so their TLSA records are the provider's. When compared on 21 October 2026, each server published one DANE-TA record that matched the issuing CA and two DANE-EE records, one of which matched the server key; the other may be a key published ahead of a rollover, the practice RFC 7671 recommends. Records, servers and keys change over time, so read the live result rather than these words. The comparison behind this choice ran the real page on five domains. Every candidate passed; `tamperbox.dev` showed both DANE-TA and DANE-EE matches and a pre-published key across three servers in about four seconds, more instructive than one-server or single-usage results and quicker than most. The reserved sample `harbor-supply.example` is used by the automated tests: three servers, the backup one presenting a renewed key its record does not name. ## For agents The Tamperbox MCP server exposes the same comparison as the `dane_checker` operation. It checks one server: pass `host` and `port` (443 by default; use 25 for a mail server); it does not resolve MX records, so look those up first. Keep the operation's limitation text with any conclusion: - A pass means one association matched with the resolver's AD flag; DNSSEC is not validated independently. - Usages 0 and 1 also need the probe's PKIX validation. - This is association evidence, not a complete DANE validation verdict. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the host travels. ## Limits One observation from one location at one moment. DNSSEC comes from the resolver's AD flag. Certificate dates and DANE-TA name checks are not evaluated, and the probe's own chain is the only chain compared. A server that does not answer is not compared, never failed. Ports outside the table are refused. Browsers do not use DANE for websites. Nothing is stored. ## References | Specification | Sections used | Status | | --- | --- | --- | | [RFC 6698](https://www.rfc-editor.org/rfc/rfc6698) The DANE TLSA record | [2.1](https://www.rfc-editor.org/rfc/rfc6698#section-2.1), [3](https://www.rfc-editor.org/rfc/rfc6698#section-3) | Updated by RFC 7218, RFC 7671 | | [RFC 7218](https://www.rfc-editor.org/rfc/rfc7218) Acronyms for DANE | [2](https://www.rfc-editor.org/rfc/rfc7218#section-2) | Current | | [RFC 7671](https://www.rfc-editor.org/rfc/rfc7671) DANE updates and operational guidance | [5.1](https://www.rfc-editor.org/rfc/rfc7671#section-5.1), [5.2](https://www.rfc-editor.org/rfc/rfc7671#section-5.2), [8.1](https://www.rfc-editor.org/rfc/rfc7671#section-8.1) | Current | | [RFC 7672](https://www.rfc-editor.org/rfc/rfc7672) SMTP security via opportunistic DANE TLS | [2.2](https://www.rfc-editor.org/rfc/rfc7672#section-2.2), [3.1.3](https://www.rfc-editor.org/rfc/rfc7672#section-3.1.3), [3.2](https://www.rfc-editor.org/rfc/rfc7672#section-3.2) | Current | | [RFC 3207](https://www.rfc-editor.org/rfc/rfc3207) SMTP STARTTLS | [4](https://www.rfc-editor.org/rfc/rfc3207#section-4) | Current | | [RFC 4035](https://www.rfc-editor.org/rfc/rfc4035) DNSSEC protocol | [3.2.3](https://www.rfc-editor.org/rfc/rfc4035#section-3.2.3) | Updated by later DNSSEC RFCs; see RFC 9364 | | [RFC 9364](https://www.rfc-editor.org/rfc/rfc9364) DNSSEC (BCP 237) | whole document | Current | | [RFC 7505](https://www.rfc-editor.org/rfc/rfc7505) Null MX | [3](https://www.rfc-editor.org/rfc/rfc7505#section-3) | Current | --- # DKIM Record Checker How the checker finds every DKIM key a domain publishes without asking for a selector, every rule it applies to a key record, what each finding means for mail delivery, and how to fix and verify each one. Canonical: https://docs.tamperbox.dev/tools/dkim-checker/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain, the DKIM-Signature header of a message it sent, or a DKIM key record to paste Outputs: A verdict for the inspected key with PASS, CHECK and FAIL chips, every key the domain publishes, the key as rows with a SHA-256 fingerprint, and the record tag by tag Limitations: Selectors are not discoverable from DNS, so a domain that signs under a selector of its own shows no key until you paste a message header; a valid key does not prove that any message is signed with it The tool page is [tamperbox.dev/dkim-checker](https://tamperbox.dev/dkim-checker). It opens on a live check of `tamperbox.dev`; replace that domain to inspect your own. This page is the long version: how discovery works, every rule applied to a key record, what each finding means, and how to fix and verify each one. <div class="tb-callout"><strong>Where processing happens:</strong> a domain or a message header is sent to the Tamperbox server, which asks public DNS once per selector and returns the records. A pasted key record is decoded and measured in your browser and never uploaded. Nothing is stored.</div> ## What the tool answers DKIM lets a receiver check that a message was signed by the domain that claims to have sent it. The signature is in the message; the public key that verifies it is in DNS, under a name called a selector: `<selector>._domainkey.<domain>`. The tool answers: 1. **Which keys does this domain publish?** Under the selectors mail services commonly use. 2. **Is the inspected key usable?** Readable, not revoked, not in testing mode, strong enough. 3. **Which key signed this message?** When you paste the message's DKIM-Signature header. 4. **Does DNS hold the key my mail service thinks it does?** By comparing the SHA-256 fingerprint. It does not verify a message. For that you need the signature, the signed headers and the body: use the [email header analyzer](https://tamperbox.dev/email-header-analyzer). ## Inputs ### A domain `example.com`. When you stop typing, the server probes the 24 common selectors, five lookups at a time. The page inspects the strongest key it finds and lists the rest under "Keys this domain publishes"; click any of them to inspect it. ### The DKIM-Signature header of a sent message Paste the header line from a message the domain sent. The page reads its `d=` tag (the signing domain) and `s=` tag (the selector), looks up exactly that key, and still probes the common selectors so you see the rest. This is the only way to be sure which key a message used. ```text DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=selector1; h=from:to:subject:date; bh=…; b=… ``` Where to find it: Gmail, open the message, the three-dot menu, "Show original"; Outlook on the web, the three-dot menu, "View message source"; Apple Mail, View, Message, All Headers. Copy the `DKIM-Signature:` line, including its continuation lines. ### A key by name `selector1._domainkey.example.com` inspects that one key, for people who already know the selector. ### A key record Paste the TXT record itself, `v=DKIM1; k=rsa; p=…`, with or without the quotes DNS tools print. It is read in the browser and shown as "Pasted record": the tool cannot know which selector it belongs to, so the verdict is about the key alone. ### Files Drop a `.txt` file anywhere on the page, or use Open file. It is read in the browser. ## Reading the result ### Verdict and chips The verdict is about the inspected key: its type and length, and whether it is valid, revoked, in testing mode or broken. The line under it says where the key was published and, for a pasted header, that it is the key named in the message. The chips repeat the key's state, then one chip per other key found, each a button that scrolls to the list. ### Findings Everything found on the inspected key, worst first, and one entry per other key the domain publishes, so a weak or testing-mode second key is never hidden by a strong first one. The [finding reference](#finding-reference) lists them all. ### The key The inspected key as rows: type, length measured from the key bytes, public exponent, allowed hashes, and the SHA-256 fingerprint of the key bytes in groups of eight hex characters. Compare the fingerprint with the one your mail service shows to confirm that DNS holds the key you expect. ### Keys this domain publishes One row per selector that answered, with the key's status and length; the inspected one is marked. Under the rows, the selectors with no key, and the count probed. "Probe again" repeats the lookups, for a temporary DNS failure or a record you just published. ### The record, tag by tag Every tag in the inspected record with its meaning: `v`, `k`, `p`, `h`, `t`, `s`, `n`. Unknown tags are listed and marked as ignored by receivers. ### History, Heal it, Take it further History logs every Break it and Heal it change with Revert and Reset input. Heal it offers the repairs the tool found: remove the testing flag, allow sha256, set the key type to RSA, correct the version tag, or restore the input before a break. Take it further carries the domain to the DMARC checker, the DANE checker and the DNSSEC checker. ## Method The server only answers DNS questions. Every rule below runs in your browser on the TXT text that comes back, or on the record you pasted, so a looked-up key and a pasted key are judged by the same code. ### Selector discovery DNS has no way to list a domain's selectors. A key lives at `<selector>._domainkey.<domain>` ([RFC 6376, Section 3.6.2.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.2.1)), and selectors are free-form names chosen by the signer ([Section 3.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.1)). The probe list is a Tamperbox choice, not an RFC rule. The tool probes these 24 names, which cover the common mail services: | Selector | Used by | | --- | --- | | `google` | Google Workspace | | `20230601`, `20221208`, `20210112` | Google's own domains, rotated by date | | `selector1`, `selector2` | Microsoft 365 (published as CNAME aliases) | | `k1`, `k2`, `k3` | Mailchimp, Mandrill | | `s1`, `s2` | SendGrid | | `default`, `dkim`, `mail`, `smtp` | Self-hosted servers, OpenDKIM defaults | | `mandrill` | Mandrill | | `mxvault` | MXroute and similar | | `zendesk1`, `zendesk2` | Zendesk | | `pm` | Postmark | | `fm1`, `fm2` | Fastmail | | `protonmail` | Proton | | `everlytickey1` | Everlytic | ### Probe results Lookups run five at a time. Each selector found gets a row with its key type, length and flags. A selector whose lookup failed (not "no record", but no answer) is counted separately, so a temporary DNS error is never reported as a missing key. This follows the split in [RFC 6376, Section 6.1.2](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.2), where a query that "fails to respond" is a TEMPFAIL and a missing record is a PERMFAIL. When every lookup fails the page reports an error, not a domain without keys. The server queries public DNS and follows CNAME aliases, so keys that a mail service hosts on its own zone through a CNAME (Microsoft 365, Amazon SES) are found. A TXT record split into several quoted strings is joined before it is read, as [Section 3.6.2.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.2.2) requires: "Strings in a TXT RR MUST be concatenated together before use with no intervening whitespace." ### Choosing the key to inspect With no selector named, the page inspects the best key found: a passing key before a key to check, a non-revoked key before a revoked one, a longer key before a shorter one. With a pasted header or a key by name, it inspects that key. Clicking a row in the list inspects that key instead. This ordering is a Tamperbox choice; no RFC ranks keys. ### Wildcard and multiple records - When five or more selectors answer and every answer is the same text, the page reports a wildcard, `*._domainkey.example.com`, as one key, not 24. A wildcard with an empty `p=` is the usual way to say "this domain signs no mail": a CHECK, with the explanation. The five-answer threshold is a Tamperbox heuristic. - A selector with two or more TXT records is FAIL, "Two or more records". [RFC 6376, Section 3.6.2.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.2.2): "TXT RRs MUST be unique for a particular selector name; that is, if there are multiple records in an RRset, the results are undefined." The usual cause is a rotated key added without removing the old one. The tool counts every TXT record at the name, DKIM or not. ### Tag rules The record is split on semicolons into `name=value` tags, following the tag-list syntax of [RFC 6376, Section 3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2). #### Tag syntax - A part without `name=value` is FAIL, "Malformed tag". - A tag that appears twice is FAIL. Section 3.2: "Tags with duplicate names MUST NOT occur within a single tag-list; if a tag name does occur more than once, the entire tag-list is invalid." - Unknown tags are listed and marked as ignored. Section 3.2: "Unrecognized tags MUST be ignored." #### Version, key type and service - `v`, when present, must be the first tag and exactly `DKIM1`; otherwise FAIL, and Heal it can correct the value. [Section 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1): "This tag MUST be the first tag in the record. Records beginning with a "v=" tag with any other value MUST be discarded." - `k` must be `rsa` or `ed25519`, in lower case. `k=RSA` is reported as an unsupported key type (FAIL) with a correction hint, and no key assessment is made. Section 3.2: "Values MUST be processed as case sensitive unless the specific tag description of semantics specifies case insensitivity." The `ed25519` value comes from [RFC 8463, Section 4.2](https://www.rfc-editor.org/rfc/rfc8463#section-4.2). - `s`, when present, must include `email` or `*`; otherwise FAIL, "Key is not enabled for email". Section 3.6.1: "Verifiers for a given service type MUST ignore this record if the appropriate type is not listed." #### Key presence and flags - A record without `p` is FAIL: no signature could ever verify. Section 3.6.1 marks `p=` "REQUIRED". - An empty `p=` is CHECK, "Key revoked". Section 3.6.1: "An empty value means that this public key has been revoked." It is CHECK, not FAIL, because revoking is a deliberate act. - `t=y` is CHECK, "Testing mode". Section 3.6.1: "Verifiers MUST NOT treat messages from Signers in testing mode differently from unsigned email, even should the signature fail to verify." The key protects less than it could. Heal it removes the flag. - `t=s` is INFO. Section 3.6.1: the "i=" domain "MUST NOT be a subdomain of "d="". The tool has no message identity to compare, so it reports the flag without verifying it. Whitespace around the colon-separated flags is allowed. #### Hash algorithms An `h=` list naming `sha1` without `sha256` is FAIL, "Only sha1 allowed". [RFC 8301, Section 3.1](https://www.rfc-editor.org/rfc/rfc8301#section-3.1): "rsa-sha1 MUST NOT be used for signing or verifying." With sha1 the only hash the key accepts, [RFC 6376, Section 6.1.2](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.2) step 6 makes every rsa-sha256 signature a PERMFAIL. Heal it removes `h=` so the default applies. ### Decoding the key bytes Key length is never estimated from the length of the text. The `p` value is base64-decoded after whitespace is removed, which [RFC 6376, Section 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) allows ("A base64string is permitted to include whitespace"). Characters outside the base64 alphabet, or a length that cannot be valid base64, fail with "The key is not valid base64". [RFC 4648, Section 3.3](https://www.rfc-editor.org/rfc/rfc4648#section-3.3): "Implementations MUST reject the encoded data if it contains characters outside the base alphabet". #### RSA keys For RSA, the bytes are read as DER. Both a SubjectPublicKeyInfo structure (with the rsaEncryption identifier) and a bare PKCS#1 `RSAPublicKey` ([RFC 8017, Appendix A.1.1](https://www.rfc-editor.org/rfc/rfc8017#appendix-A.1.1)) are accepted. The modulus is measured to the exact bit, leading zero bytes ignored, and the public exponent is shown. Structural errors are reported directly: "The key data is truncated", "Invalid DER length", or "The key is not an RSA key; set k= to its type" when the algorithm identifier is something else. [RFC 6376, Section 6.1.2](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.2) step 5: a record that "does not adhere to the format defined in this specification" MUST be ignored with PERMFAIL. #### Ed25519 keys For `k=ed25519` the decoded key must be exactly 32 bytes. [RFC 8463, Section 4.2](https://www.rfc-editor.org/rfc/rfc8463#section-4.2): "The p= value in the key record is the Ed25519 public key encoded in base64." #### Common causes Truncated keys are the most common real-world failure. They come from a control panel that cut a long value at 255 characters, or dropped one of the quoted strings a long TXT record is split into. Another frequent cause is `k=ed25519` on a key that is really RSA: when the key text starts with `MI`, the usual opening of DER, Heal it offers `k=rsa`. ### Key strength The thresholds come from [RFC 8301, Section 3.2](https://www.rfc-editor.org/rfc/rfc8301#section-3.2): "Signers MUST use RSA keys of at least 1024 bits for all keys. Signers SHOULD use RSA keys of at least 2048 bits." and "Verifiers MUST NOT consider signatures using RSA keys of less than 1024 bits as valid signatures." | Key | Severity | Title | | --- | --- | --- | | RSA under 1024 bits | FAIL | N-bit RSA key: receivers ignore it | | RSA 1024 to 2047 bits | CHECK | N-bit RSA key: accepted, but 2048 is the recommendation | | RSA 2048 bits or more | PASS | N-bit RSA key | | Ed25519 | PASS | Ed25519 key, with a note to sign with RSA as well, because not every receiver verifies Ed25519 yet | The Ed25519 note is a Tamperbox recommendation. [RFC 8463, Section 5](https://www.rfc-editor.org/rfc/rfc8463#section-5) says "verifiers MUST implement the Ed25519-SHA256 algorithm", and [Section 6](https://www.rfc-editor.org/rfc/rfc8463#section-6) describes signing twice, under two selectors, for backward compatibility. ### Fingerprint The page computes a SHA-256 digest of the decoded key bytes in the browser and shows it in groups of eight hex characters. Compare it with the fingerprint your mail service shows to confirm that DNS holds the key you expect. It says nothing about whether outgoing mail is signed with it. No RFC defines a DKIM key fingerprint; this is a Tamperbox convenience. ## Standards and conformance The checker implements the key record half of DKIM: the record a verifier fetches in step 1 of [RFC 6376, Section 6.1.2](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.2) and the checks of steps 3, 5 and 7 on it. It never sees a message body or a signature value, so hash computation ([Section 3.7](https://www.rfc-editor.org/rfc/rfc6376#section-3.7)) and signature verification ([Section 6.1.3](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.3)) are out of scope. Lookups go to our server, which asks public DNS and returns the TXT text; every rule then runs in the browser. A pasted record never leaves the browser. ### RFC 6376: key record syntax [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376) is an Internet Standard (STD 76), updated by RFC 8301, RFC 8463, RFC 8553 and RFC 8616. RFC 8553 (underscored DNS names) and RFC 8616 (internationalized addresses) do not change the key record, so the tool has nothing to apply from them. | Section | Requirement | What the tool does | | --- | --- | --- | | [3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2) | Tag-list syntax, no duplicates, unknown tags ignored | Parsed locally; malformed or duplicate tags FAIL, unknown tags listed as ignored | | [3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) `v=` | First tag, exactly `DKIM1` | FAIL when not first or not `DKIM1` | | [3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) `k=` | Default `rsa`; unknown types ignored | Accepts `rsa` and `ed25519` only, case-sensitive; anything else FAIL | | [3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) `h=` | Colon-separated list; default all algorithms | FAIL when `sha1` is listed without `sha256` | | [3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) `p=` | Required; empty means revoked | Missing FAIL; empty CHECK; otherwise decoded and measured | | [3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) `s=` | Must list `email` or `*` for mail | FAIL when neither is listed | | [3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) `t=` | Flags `y` and `s` | `y` CHECK, `s` INFO (not verified) | | [3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) `n=` | Notes for people | Shown, not judged | ### RFC 6376: DNS binding and lookup | Section | Requirement | What the tool does | | --- | --- | --- | | [3.6.2.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.2.1) | Key at `selector._domainkey.domain` | Looked up on our server for 24 common selectors, plus the one named | | [3.6.2.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.2.2) | Strings concatenated; one TXT record per selector | Strings joined; two or more records FAIL | | [6.1.2](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.2) step 2 | No answer is TEMPFAIL | Counted as "could not be checked", never as a missing key | | [6.1.2](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.2) step 3 | No record is PERMFAIL | FAIL "No record at the selector" when a selector was named | | [6.1.2](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.2) step 7 | Empty `p=` is PERMFAIL (key revoked) | CHECK, because revoking is deliberate | From a pasted DKIM-Signature header the tool reads only `d=` and `s=` ([Section 3.5](https://www.rfc-editor.org/rfc/rfc6376#section-3.5)). It does not compare the header's `a=` with the key's `h=` and `k=` (steps 6 and 8), does not read `q=`, and does not check `i=` against `t=s`. ### RFC 8301: algorithms and key sizes [RFC 8301](https://www.rfc-editor.org/rfc/rfc8301) updates RFC 6376 Sections 3.3 and 3.3.3. The tool applies [Section 3.1](https://www.rfc-editor.org/rfc/rfc8301#section-3.1) through the sha1-only rule and [Section 3.2](https://www.rfc-editor.org/rfc/rfc8301#section-3.2) through the RSA thresholds: under 1024 bits FAIL, 1024 to 2047 CHECK (the SHOULD), 2048 and more PASS. The older floor in [RFC 6376, Section 3.3.3](https://www.rfc-editor.org/rfc/rfc6376#section-3.3.3), where verifiers had to accept 512-bit keys, is not used. RFC 8301 only obliges verifiers to handle keys up to 4096 bits; the tool still reports a longer key as PASS and does not warn that some receivers may refuse it. ### RFC 8463: Ed25519 [RFC 8463](https://www.rfc-editor.org/rfc/rfc8463) adds `k=ed25519` ([Section 4.2](https://www.rfc-editor.org/rfc/rfc8463#section-4.2)). The tool checks that `p=` decodes to 32 bytes, the public key size of [RFC 8032, Section 5.1.5](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5). It does not decode the bytes as a curve point ([RFC 8032, Section 5.1.3](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.3)), so 32 random bytes pass. ### RFC 8017 and RFC 4648: key encoding RFC 6376 Section 3.6.1 says the `rsa` type carries an `RSAPublicKey` and cites RFC 3447, which [RFC 8017](https://www.rfc-editor.org/rfc/rfc8017) obsoletes. Its own example in [Appendix C](https://www.rfc-editor.org/rfc/rfc6376#appendix-C) publishes a SubjectPublicKeyInfo, which is what mail services issue. The tool accepts both forms. It reads the modulus and exponent ([RFC 8017, Section 3.1](https://www.rfc-editor.org/rfc/rfc8017#section-3.1)) but does not check that the exponent lies between 3 and n - 1. Base64 follows [RFC 4648, Section 4](https://www.rfc-editor.org/rfc/rfc4648#section-4). Non-alphabet characters are rejected ([Section 3.3](https://www.rfc-editor.org/rfc/rfc4648#section-3.3)). Missing `=` padding is added before decoding, which is more lenient than [Section 3.2](https://www.rfc-editor.org/rfc/rfc4648#section-3.2) ("Implementations MUST include appropriate pad characters"); a receiver with a strict decoder may refuse such a key. ### Where the tool differs from the RFCs - **Tag names are case-insensitive in the tool.** `V=DKIM1; P=…` is read as `v` and `p`, while [RFC 6376, Section 3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2) says "Tags MUST be interpreted in a case-sensitive manner." A receiver would see no `p=` tag. Values, including `k=`, stay case-sensitive. - **Flags are exact colon-separated tokens.** `t=x-y` is ignored, while `t=y` and `t=s:y` activate testing mode under [section 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1). - **Multiple records are FAIL, not "undefined".** Section 3.6.2.2 leaves the result undefined, and Section 6.1.2 step 4 lets a verifier pick one or try each. The tool is stricter, because the outcome then depends on the receiver. - **Unknown `k=` is FAIL.** The RFC says unknown key types "MUST be ignored"; for mail, that means no usable key, so FAIL reflects the outcome. - **Malformed RSA structures** receive readable key errors, including missing BIT STRING and missing exponent, rather than a JavaScript exception title. ### RFC 9989: DMARC context DMARC itself is not evaluated. Only the "No key under the common selectors" finding mentions it: without a key, the domain has no DKIM-Authenticated Identifier ([RFC 9989, Section 4.4.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.4.1)), so DMARC can pass only through SPF ([Section 5.3.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.5)). [RFC 9989](https://www.rfc-editor.org/rfc/rfc9989) obsoletes RFC 7489. Use the [DMARC checker](https://docs.tamperbox.dev/tools/dmarc-checker/) for the policy. ## Finding reference Each finding the checker can emit, grouped by what it judges, with what it means for mail signed with the key. "none" in the RFC section column marks a Tamperbox recommendation or method, not an RFC rule. ### Key strength and state What receivers do with the published key, by its type, size and flags. | Finding | Severity | RFC section | What it means for mail delivery | Fix | | --- | --- | --- | --- | --- | | N-bit RSA key (2048 or more) | PASS | [RFC 8301, 3.2](https://www.rfc-editor.org/rfc/rfc8301#section-3.2) | Receivers can verify signatures made with it | | | Ed25519 key | PASS | [RFC 8463, 4.2](https://www.rfc-editor.org/rfc/rfc8463#section-4.2); the dual-signing note is none (Tamperbox) | Strong; some receivers cannot verify it yet | Also sign with RSA under a second selector | | N-bit RSA key (1024 to 2047) | CHECK | [RFC 8301, 3.2](https://www.rfc-editor.org/rfc/rfc8301#section-3.2) | Still accepted; scored down by some receivers | Rotate to a 2048-bit key under a new selector | | N-bit RSA key (under 1024) | FAIL | [RFC 8301, 3.2](https://www.rfc-editor.org/rfc/rfc8301#section-3.2) | Receivers ignore the key; mail is treated as unsigned | Rotate to a 2048-bit key | | Key revoked (empty p=) | CHECK | [RFC 6376, 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) | Signatures with this selector fail on purpose | Fine if retired; republish the key if mail still uses it | | Testing mode (t=y) | CHECK | [RFC 6376, 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) | Failures may be treated as unsigned; weaker protection | Remove t=y once signing works | | Strict DKIM identity domain (t=s) | INFO | [RFC 6376, 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) | The signing identity must match the signing domain exactly | Nothing, unless subdomains sign with this key | ### Key record syntax Problems that stop a receiver from loading the key at all. #### Record tags | Finding | Severity | RFC section | What it means for mail delivery | Fix | | --- | --- | --- | --- | --- | | Malformed tag | FAIL | [RFC 6376, 3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2) | The record is not a valid tag list | Write each part as name=value | | Tag appears twice | FAIL | [RFC 6376, 3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2) | The whole record is invalid | Keep one copy of the tag | | Only sha1 allowed | FAIL | [RFC 8301, 3.1](https://www.rfc-editor.org/rfc/rfc8301#section-3.1) | Receivers reject sha1 signatures | Allow sha256, or remove h= | | No p= key | FAIL | [RFC 6376, 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) | No signature can verify | Publish the public key | | Unsupported key type | FAIL | [RFC 6376, 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) | Case-sensitive: `k=RSA` is not `k=rsa` | Use rsa or ed25519 in lower case | | v=DKIM1 must be first | FAIL | [RFC 6376, 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) | Receivers ignore the record | Move v= to the front | | v= other than DKIM1 | FAIL | [RFC 6376, 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) | Only DKIM1 is defined | Set v=DKIM1 | | Key is not enabled for email | FAIL | [RFC 6376, 3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1) | s= excludes email | Set s=email, or remove s= | #### Key data | Finding | Severity | RFC section | What it means for mail delivery | Fix | | --- | --- | --- | --- | --- | | The key is not valid base64 | FAIL | [RFC 4648, 3.3](https://www.rfc-editor.org/rfc/rfc4648#section-3.3) | Receivers cannot load the key | Re-copy the record from your mail service | | The key data is truncated | FAIL | [RFC 8017, A.1.1](https://www.rfc-editor.org/rfc/rfc8017#appendix-A.1.1) | Receivers cannot load the key | Publish the full value; split it into quoted strings if your DNS panel limits a string to 255 characters | | The key is not an RSA key; set k= to its type | FAIL | [RFC 6376, 6.1.2](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.2) | The k= tag and the bytes disagree | Set k= to the real type | | An Ed25519 key is 32 bytes | FAIL | [RFC 8463, 4.2](https://www.rfc-editor.org/rfc/rfc8463#section-4.2) | The bytes are not an Ed25519 key | Set k=rsa, or publish the right key | ### Selectors and discovery Findings about where the key lives and which selectors answer. | Finding | Severity | RFC section | What it means for mail delivery | Fix | | --- | --- | --- | --- | --- | | Two or more records at the selector | FAIL | [RFC 6376, 3.6.2.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.2.2) | Results are undefined; receivers may pick either record | Remove the old record | | No record at the selector | FAIL | [RFC 6376, 6.1.2](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.2) | Mail signed with this selector fails at every receiver | Publish the key, or sign with the right selector | | No key under the common selectors | FAIL | none (Tamperbox probe list) | The domain sends unsigned mail, or signs under its own selector | Paste a message header to check the exact key | | selector: key (another key found) | INFO, CHECK or FAIL | none (Tamperbox) | Another service signs for the domain with this key | Inspect it; each key needs the same attention | ## Guide ### Finding the key behind a message When someone says "your mail fails DKIM", the key that matters is the one named in that message. 1. Open the message's source (Gmail: Show original; Outlook: View message source; Apple Mail: All Headers). 2. Copy the `DKIM-Signature:` line with its continuation lines and paste it into the box. The page inspects exactly that key. 3. If the verdict is "No DKIM key", the selector in the message has no record: the service is signing with a key that is not in DNS. Publish the record your service gave you under that exact selector. 4. If the key is there but weak, revoked or in testing mode, follow the section for that finding below. ### Rotating to a 2048-bit key Never replace a key in place: mail signed with the old key is still in transit. 1. In your mail service, generate a new 2048-bit key. It gives you a new selector and a TXT record. 2. Publish the record. Check the domain here: the new selector appears in the list with a PASS. 3. Switch signing to the new selector in the service. 4. After a few days, revoke the old selector by publishing `v=DKIM1; p=` under it. Check: the old key shows "Key revoked". 5. After a few weeks, delete the old record. Confirm the switch by pasting the header of a freshly sent message: the `s=` tag should be the new selector. ### A revoked key An empty `p=` means someone retired this selector on purpose. If no mail uses it, nothing to do: delete the record when convenient. If mail still uses it, your service is signing with a key receivers refuse: republish the current public key under that selector, or switch the service to a selector that has one. ### Testing mode `t=y` belongs to the first days of a rollout. Once a few messages verify (paste their headers to see the key inspected, then confirm with your receiver's reports), remove the flag. Heal it shows the corrected record; publish it in DNS. ### Only sha1 allowed Remove the `h=` tag, or make it `h=sha256` or `h=sha1:sha256`. Heal it shows the corrected record. Nothing changes in the mail service; the record only declares what receivers may accept. ### Truncated or unreadable key 1. Copy the record again from your mail service and compare it character by character with what DNS returns (The record, tag by tag shows the published `p=`). 2. If your DNS panel limits a TXT string to 255 characters, split the value into two quoted strings: `"v=DKIM1; k=rsa; p=MIIBIjAN…" "…IDAQAB"`. Receivers join them. 3. If `k=ed25519` and the key starts with `MI`, the key is RSA: set `k=rsa` (Heal it offers it). 4. Publish, then Probe again. ### Two records at one selector A rotated key was added without removing the old one. Delete the old record so exactly one remains, then Probe again. ### No key under the common selectors Either the domain sends no mail, or it signs under a selector the probe does not try. - If the domain sends mail, paste the header of a message it sent: the exact selector is in it. Many services use dated or random selectors. - If it sends no mail, publish `*._domainkey.example.com TXT "v=DKIM1; p="` and a DMARC policy with `p=reject`, so nobody can sign as the domain. ### Google Workspace, Microsoft 365, and the rest | Service | Selector | How the record is published | | --- | --- | --- | | Google Workspace | `google` | TXT record the admin console gives you | | Microsoft 365 | `selector1`, `selector2` | Two CNAME records pointing into `onmicrosoft.com`; the key lives there | | Mailchimp | `k1`, `k2`, `k3` | CNAME to Mailchimp | | SendGrid | `s1`, `s2` | CNAME to SendGrid | | Postmark | `pm` | TXT | | Fastmail | `fm1`, `fm2` | CNAME to Fastmail | | Proton | `protonmail` | CNAME to Proton | | Amazon SES | three random selectors | CNAME to SES; not in the common list, so paste a header | Because the probe follows CNAME aliases, a CNAME-published key appears like any other. ### The mail server's own certificate DKIM protects the message; the connection that carries it is protected by the mail server's TLS certificate, which fails in its own ways. Check it with the [SSL Certificate Checker on a mail port](https://docs.tamperbox.dev/tools/ssl-checker/#a-host-name-with-a-mail-port), and the TLSA records that pin it with the [DANE checker](https://tamperbox.dev/dane-checker). ### Break it cases Each case is built from the key you entered or looked up, so the finding looks the way it would for you. | Case | What it does to your record | Heal it offers | | --- | --- | --- | | 1024-bit key | Loads a 1024-bit sample key | Restore input before this break | | Revoked key | Empties `p=` | Restore | | Testing flag | Adds `t=y` | Remove testing mode (t=y) | | Truncated key | Cuts the key in half | Restore | | Only sha1 | Adds `h=sha1` | Allow sha256 | | Wrong key type | Sets `k=ed25519` on an RSA key | Set k=rsa (the key is RSA) | ## Worked example The page opens on a live check of `tamperbox.dev`. Its published records and findings can change over time. For the deterministic walkthrough below, enter `harbor-supply.example`. This reserved `.example` domain is answered from synthetic data in your browser; it sends no live lookup. It publishes: - `google`: a 2048-bit RSA key, inspected. **2048-bit RSA key: valid and strong enough.** - `s1`: a 1024-bit RSA key in testing mode, listed beside it and reported as a CHECK finding ("s1: 1024-bit RSA, testing"), because a second service signs for the domain with a weaker key. Click `s1` to inspect it: the verdict becomes "1024-bit RSA key: rotate when you can", with Testing mode as a second finding and Heal it offering to remove the flag. Replace the sample with your own domain and every section, card and link is rewritten for it. ## For agents The Tamperbox MCP server runs the same checks. Search its catalog for the DKIM operation, inspect the input schema, and call it with the domain and, when known, the selector. Keep the warning block with any conclusion: - A valid key does not prove that any message is signed with it. Message verification needs the signature and the signed content. - Discovery tries the 24 common selectors; a domain can publish others. - DNS evidence is one answer from one public resolver at one moment. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the domain travels. ## Limits - Selectors are not discoverable from DNS; discovery finds the common ones only. - A valid key does not prove that mail is signed with it, or that a message passes. - A pasted record is measured in the browser and says nothing about what DNS serves. - One DNS answer, from one public resolver, at one moment. - Nothing is stored. ## References - [RFC 6376, DomainKeys Identified Mail (DKIM) Signatures](https://www.rfc-editor.org/rfc/rfc6376). Internet Standard, STD 76; updated by RFC 8301, RFC 8463, RFC 8553 and RFC 8616. Sections used: [3.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.1), [3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2), [3.3.3](https://www.rfc-editor.org/rfc/rfc6376#section-3.3.3), [3.5](https://www.rfc-editor.org/rfc/rfc6376#section-3.5), [3.6.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.1), [3.6.2.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.2.1), [3.6.2.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.2.2), [6.1.2](https://www.rfc-editor.org/rfc/rfc6376#section-6.1.2) and [Appendix C](https://www.rfc-editor.org/rfc/rfc6376#appendix-C). - [RFC 8301, Cryptographic Algorithm and Key Usage Update to DKIM](https://www.rfc-editor.org/rfc/rfc8301). Standards Track; updates RFC 6376. Sections used: [3.1](https://www.rfc-editor.org/rfc/rfc8301#section-3.1) and [3.2](https://www.rfc-editor.org/rfc/rfc8301#section-3.2). - [RFC 8463, A New Cryptographic Signature Method for DKIM](https://www.rfc-editor.org/rfc/rfc8463). Standards Track; updates RFC 6376. Sections used: [4.2](https://www.rfc-editor.org/rfc/rfc8463#section-4.2), [5](https://www.rfc-editor.org/rfc/rfc8463#section-5) and [6](https://www.rfc-editor.org/rfc/rfc8463#section-6). - [RFC 8017, PKCS #1: RSA Cryptography Specifications Version 2.2](https://www.rfc-editor.org/rfc/rfc8017). Informational; obsoletes RFC 3447, which RFC 6376 cites. Sections used: [3.1](https://www.rfc-editor.org/rfc/rfc8017#section-3.1) and [Appendix A.1.1](https://www.rfc-editor.org/rfc/rfc8017#appendix-A.1.1). - [RFC 8032, Edwards-Curve Digital Signature Algorithm (EdDSA)](https://www.rfc-editor.org/rfc/rfc8032). Informational. Sections used: [5.1.3](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.3) (not applied) and [5.1.5](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5). - [RFC 4648, The Base16, Base32, and Base64 Data Encodings](https://www.rfc-editor.org/rfc/rfc4648). Standards Track. Sections used: [3.2](https://www.rfc-editor.org/rfc/rfc4648#section-3.2), [3.3](https://www.rfc-editor.org/rfc/rfc4648#section-3.3) and [4](https://www.rfc-editor.org/rfc/rfc4648#section-4). - [RFC 9989, Domain-based Message Authentication, Reporting, and Conformance (DMARC)](https://www.rfc-editor.org/rfc/rfc9989). Standards Track, May 2026; obsoletes RFC 7489 and RFC 9091. Sections used: [4.4.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.4.1) and [5.3.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.5). - Tamperbox guides: [Why is my DKIM key failing?](https://tamperbox.dev/guides/fix-dkim-key-failures) and [DMARC rollout: from p=none to reject](https://tamperbox.dev/guides/dmarc-monitoring-to-reject) --- # DMARC Checker & Generator How the checker finds and grades a DMARC record, every rule applied to its tags, what each finding means for spoofed and legitimate mail, and how the builder and the path to enforcement write the next record. Canonical: https://docs.tamperbox.dev/tools/dmarc-checker/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain, or a DMARC record to paste Outputs: A verdict with PASS, CHECK and FAIL chips, the findings with their fixes, the path to enforcement, the builder, the record to publish, and the record tag by tag Limitations: The tool reads the policy, not the aggregate reports, so it cannot tell whether legitimate mail already passes; a bounded DNS tree walk finds parent-domain policy when needed, and external report authorisation records are named but not looked up; pct is warned as obsolete, and t and psd are recognized The tool page is [tamperbox.dev/dmarc-checker](https://tamperbox.dev/dmarc-checker). It opens on a live check of `tamperbox.dev`; replace that domain to inspect your own. This page is the long version: how the record is found and read, every rule applied to it, what each finding means, and how the builder and the path to enforcement write the next record. <div class="tb-callout"><strong>Where processing happens:</strong> a domain is sent to the Tamperbox server, which asks public DNS for the TXT record at <code>_dmarc.<domain></code>. A pasted record is parsed and graded in your browser, and every draft you build stays on the page. Nothing is stored, and copying a draft does not publish it.</div> ## What the tool answers DMARC tells receivers what to do with mail that fails both aligned SPF and aligned DKIM, and where to send reports about it. The tool answers: 1. **Is there a valid record, and what does it say?** One record at the exact name, every tag explained. 2. **How much does it protect?** The policy, the percentage it applies to, and the subdomain policy. 3. **Will you hear about failures?** Aggregate report addresses, their format, and whether an outside receiver needs to authorise them. 4. **What is the next safe step?** A draft record for each step from monitoring to reject, with every change kept in History. It does not read aggregate reports, so it cannot say whether your legitimate mail already passes. ## Inputs ### A domain `example.com`. When you stop typing, or on Enter, the server reads the TXT records at `_dmarc.example.com` and keeps the ones that begin with `v=DMARC1`. Two or more is a finding; none shows a starting draft. ### A DMARC record Paste the record itself, with or without quotes: `v=DMARC1; p=none; rua=mailto:dmarc@example.com`. It is parsed in the browser and shown as "Pasted record". Publication, and the policy a parent domain may publish, are not checked. ### Files Drop a `.txt` file anywhere on the page, or use Open file. It is read in the browser. ## Reading the result ### Verdict and chips The verdict names the policy's effect: no policy, monitoring only, quarantining or rejecting a share or all of failing mail, or an invalid record, followed by where the record came from (published, pasted, or a draft). The chips show the policy with its percentage, whether reports are on, and whether you are looking at the published record, a pasted one, or a draft; each one is a button that scrolls to the section that explains it. ### Findings Everything found, worst first; passes fold into one line. The `p=none` finding carries a button that moves the draft one step forward. The [finding reference](#finding-reference) lists them all. ### Take it further Links that carry a derived value into another tool: the mail route of the report mailbox's domain, BIMI readiness for the domain once the policy enforces, and DNSSEC on the zone. Each opens the destination with the value already in its box; nothing is put in the URL. ### History and Heal it History logs every change: a rollout step, a builder edit, a Break it case or a Heal it repair, each with the record it replaced. Revert undoes the newest change and returns the draft to the record before it; Reset input returns to the published or pasted record. Heal it offers the repairs the tool found: add `p=none`, correct a misspelt policy, remove obsolete `pct`, make `rua` a `mailto:` address, choose which value to keep when a tag is duplicated, move a misplaced version tag to the front. ### Path to enforcement Four targets, each a complete record built from the current tags: Monitor (`p=none`), Test quarantine (`p=quarantine; t=y`), Quarantine all (`p=quarantine`), Reject (`p=reject`). The current step is marked "You are here". Choosing a target applies it as a draft. The test step requests one level less enforcement under [RFC 9989 section 4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7), so quarantine in test mode requests monitoring. ### Build the record Policy, subdomain policy, percentage, aggregate and failure report addresses, DKIM and SPF alignment, and failure options. Every change applies at once and is graded like a published record. ### Publish this record The draft as one TXT record, with the name to publish it at and a copy button. Copying does not publish. ### The record, tag by tag Every tag with its label and meaning; unknown tags are marked as ignored by receivers. ## Method Each rule below names the section of [RFC 9989](https://www.rfc-editor.org/rfc/rfc9989), the DMARC specification, that it comes from. RFC 9989 obsoletes RFC 7489, the Informational predecessor; where the tool still follows RFC 7489, the rule says so, and [Standards and conformance](#standards-and-conformance) lists every difference. ### Finding the record The server asks public DNS, through one DNS-over-HTTPS resolver, for TXT records at exactly `_dmarc.<domain>` ([RFC 9989, section 4.5](https://www.rfc-editor.org/rfc/rfc9989#section-4.5)). A record split into several strings is joined first: "the module performing DMARC evaluation MUST concatenate these strings" (section 4.5). Only records that begin with `v=DMARC1` are kept, as in step 2 of the [DNS tree walk, section 4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10). - Two or more records are discarded at that name and discovery continues toward a parent policy, following section 4.10. No first-record-wins policy is inferred. - No record: the verdict is "No DMARC record" and a starting draft, `v=DMARC1; p=none`, is prepared for the builder. The lookup moves up the tree, bounded to eight queries, and stops at an explicit `psd=n` or `psd=y` boundary. [Section 4.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.10.1) has receivers walk from the Author Domain to its Organizational Domain and then to a public suffix domain when no record exists at the exact name. The selected source domain is displayed. Domain existence is not queried, so inherited policy is shown for existing subdomains and `np` remains a limitation. ### Version and tag syntax The record is split on semicolons, and each part must be `name=value`, as in the formal definition of [section 4.8](https://www.rfc-editor.org/rfc/rfc9989#section-4.8). - The first tag must be exactly `v=DMARC1`, case-sensitive. [Section 4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7): "This tag MUST be the first tag in the list." If it is not, "the entire record MUST be ignored." The tool stops: "Not a DMARC record". Heal it can move a misplaced `v=DMARC1` to the front. - A part without `=`: FAIL, "Not a tag: X". - A tag that appears twice: FAIL, "name appears twice". DMARC uses the DKIM tag-list syntax (section 4.7), and [RFC 6376, section 3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2) says "if a tag name does occur more than once, the entire tag-list is invalid." Identical duplicates can be removed; conflicting values get one repair per value ("Keep p=none", "Keep p=reject"). While duplicates remain, the policy is not graded and the builder, the path to enforcement and the record to publish are hidden. ### Tag values - `p`, `sp` and `np` accept only `none`, `quarantine` or `reject` (the `dmarc-request` rule of section 4.8); `adkim` and `aspf` only `r` or `s` (`dmarc-rors`). Anything else: FAIL, "name=value is not valid". - No `p`: INFO, "No p= policy: defaults to none". An otherwise valid record defaults to monitoring under [section 4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7). - `pct` produces CHECK, "pct=X is obsolete". It never reduces enforcement; [RFC 9989 appendix A.6](https://www.rfc-editor.org/rfc/rfc9989#appendix-A.6) removes percentage sampling. - A tag outside `v`, `p`, `sp`, `np`, `t`, `psd`, `pct`, `rua`, `ruf`, `adkim`, `aspf`, `fo`, `rf`, `ri`: CHECK, "Unknown tag X". Section 4.7: "unknown tags MUST be ignored." ### Policy strength The grade follows [section 4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7). Missing `p` defaults to `none`; `pct` is ignored. Test mode `t=y` reduces reject to quarantine and quarantine to none. The display reports a requested policy, not a guarantee of receiver handling. | Record | Severity | Title | Basis | | --- | --- | --- | --- | | `p=reject`, no test mode | PASS | p=reject | Section 4.7, `p` | | `p=quarantine`, no test mode | PASS | p=quarantine | Section 4.7, `p` | | `p=quarantine; t=y` | CHECK | DMARC test mode (t=y), p=none only monitors | Section 4.7, `t` | | `p=reject; t=y` | CHECK | DMARC test mode (t=y), p=quarantine | Section 4.7, `t` | | `p=none` | CHECK | p=none only monitors | [Section 3.2.12](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.12), Monitoring Mode | | `sp=none` with an enforcing `p` | CHECK | sp=none on subdomains | Section 4.7, `sp` | | `adkim=s` or `aspf=s` | INFO | Strict alignment | [Section 3.2.10.2](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.10.2) | For `sp`, section 4.7 says: "If both the "sp" tag is absent and the "np" tag is either absent or not applicable, the policy specified by the "p" tag MUST be applied for subdomains." So `sp=none` beside an enforcing `p` opens every existing subdomain on purpose. The `p=none` and `sp=none` grades are Tamperbox recommendations: the specification allows both. ### Report addresses - No `rua`: CHECK, "No rua reports". Section 4.7: "If the tag is not provided, Mail Receivers MUST NOT generate aggregate feedback reports for the domain." Reports are optional in the specification; the CHECK is a Tamperbox recommendation, since [section 5.1.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.1.5) has the Domain Owner collect and analyse them before enforcing. - Each comma-separated `rua` entry ([section 4.6](https://www.rfc-editor.org/rfc/rfc9989#section-4.6)) must be a `mailto:` URI with one `@`, optionally followed by a size limit such as `!10m`. Anything else: FAIL, "Invalid report address X". This is stricter than the specification, where "Any valid URI can be specified" and "URIs involving schemes not supported by Mail Receivers MUST be ignored" (section 4.7). The size limit is obsolete syntax that reporters ignore (section 4.8). - An address on a domain that is neither the checked domain nor one of its subdomains: INFO, "Reports go to X", naming the record the receiving domain must publish, `<domain>._report._dmarc.<receiving-domain>`. [RFC 9990, section 4](https://www.rfc-editor.org/rfc/rfc9990#section-4) says that when the Organizational Domains differ, "the following verification steps MUST be taken". That record is not looked up. For a pasted record the domain is unknown, so no note is made. - Otherwise: PASS, "N report addresses". `ruf`, `fo`, `rf` and `ri` are explained but not validated. ### The builder and the drafts The builder writes tags in a fixed order (`v`, `p`, `sp`, `np`, `t`, `psd`, `pct`, `rua`, `ruf`, `adkim`, `aspf`, `fo`, `rf`, `ri`), keeps unknown tags at the end, and leaves out tags that only repeat a default (`pct=100`, `adkim=r`, `aspf=r`, `fo=0`, `rf=afrf`, `ri=86400`). The `adkim`, `aspf` and `fo` defaults are those of [section 4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7); the `pct`, `rf` and `ri` defaults are RFC 7489's. Starting with `v=DMARC1` keeps every draft valid under section 4.7. A draft is graded by the same rules as a published record. The problems of the published record (duplicates, multiple records) are not carried into the draft's findings, except the multiple-records finding, which the draft cannot fix. ## Standards and conformance The tool reads one DMARC record and grades its text. It is not a mail receiver: it evaluates no message, so SPF and DKIM results and identifier alignment are never computed. This section lists, per specification, what the tool implements, where it stops and where it is stricter or more lenient than the text. DMARC was published as [RFC 7489](https://www.rfc-editor.org/rfc/rfc7489) (Informational, 2015). In May 2026 three Standards Track documents obsoleted it: [RFC 9989](https://www.rfc-editor.org/rfc/rfc9989) for the mechanism (which also obsoletes RFC 9091, the experimental public suffix domain policy), [RFC 9990](https://www.rfc-editor.org/rfc/rfc9990) for aggregate reports and [RFC 9991](https://www.rfc-editor.org/rfc/rfc9991) for failure reports, which also updates RFC 6591. The tool's tag table still follows RFC 7489 in several places, listed below. ### RFC 9989: finding the record | Section | Requirement | What the tool does | | --- | --- | --- | | [4.5](https://www.rfc-editor.org/rfc/rfc9989#section-4.5) | Records are TXT at `_dmarc.<domain>`; strings MUST be concatenated | Looked up on the Tamperbox server through one public resolver; strings joined | | [4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10), step 2 | Records not starting with `v=DMARC1` are discarded; several records are all discarded | Same filter; multiple records at a name are discarded | | [4.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.10.1) | Without a record at the Author Domain, walk to the Organizational Domain and the public suffix domain | Implemented with at most eight queries | | [4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10) | The tree walk replaces the Public Suffix List and stops at a record with `psd=y` or `psd=n` | Implemented; source domain is shown | | [3.2.13](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.13) | A non-existent domain is one answering NXDOMAIN; `np` applies to those | Not checked; `np` is only validated | | [5.3.1](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.1) | A U-label Author Domain MUST be converted to an A-label | The domain is converted to A-labels before the lookup | The lookup accepts `v` or `V` as the version tag name but requires the case-sensitive value `DMARC1`, following [section 4.8](https://www.rfc-editor.org/rfc/rfc9989#section-4.8). ### RFC 9989: record format and tag values All parsing happens in the browser, from the text the server returned or the text you pasted. | Section | Requirement | What the tool does | | --- | --- | --- | | [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7), `v` | First tag, value exactly `DMARC1`, else ignore the record | Same: the record is not read | | [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) | Unknown tags MUST be ignored | CHECK finding, record still graded | | [4.8](https://www.rfc-editor.org/rfc/rfc9989#section-4.8) | Syntax errors MUST be discarded in favour of defaults or ignored | Stricter: a malformed part or an invalid value is a FAIL and makes the verdict invalid | | [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7), `p` | Missing `p` is treated as `p=none` | Defaults to monitoring with an informational finding | | [4.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.10.1) | Invalid `p`, `sp` or `np` with a valid `rua`: act as `p=none`; otherwise no DMARC processing | Not modelled; the tool reports the record as invalid | | [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7), `adkim`, `aspf` | `r` or `s`, default `r` | Validated; default left out of drafts | | [4.8](https://www.rfc-editor.org/rfc/rfc9989#section-4.8), `fo` | `0` or `1` with `d` and `s`, colon-separated; ignored without `ruf` | Explained, not validated | | [4.6](https://www.rfc-editor.org/rfc/rfc9989#section-4.6), `rua` and `ruf` | Comma-separated URIs; any valid URI | `rua` must be `mailto:`; `ruf` is not checked | | [4.8](https://www.rfc-editor.org/rfc/rfc9989#section-4.8) | `!size` suffix is obsolete; reporters ignore it | Accepted without comment | ### RFC 9989: tags removed and added since RFC 7489 [Appendix C.5](https://www.rfc-editor.org/rfc/rfc9989#appendix-C.5) lists the tag changes. Under RFC 9989 a removed tag is simply an unknown tag, so receivers ignore it. | Tag | Change in RFC 9989 | What the tool does | | --- | --- | --- | | `pct` | Removed ([appendix C.5.2](https://www.rfc-editor.org/rfc/rfc9989#appendix-C.5.2), [A.6](https://www.rfc-editor.org/rfc/rfc9989#appendix-A.6)) | Warned as obsolete and ignored for grading; no percentage rollout step | | `rf` | Removed | Known tag with an explanation; not flagged | | `ri` | Removed | Known tag with an explanation; not flagged | | `t` | Added: `y` asks receivers to apply one level below the policy; default `n` | Validated and used to downgrade the effective policy | | `np` | Added, imported from RFC 9091 | Known; values validated; not graded | | `psd` | Added: `y`, `n` or `u`, default `u` | Validated and used to stop discovery | Appendix A.6 explains the replacement: the `t` values `y` and `n` are "meant to be analogous" to `pct=0` and `pct=100`. A receiver that follows RFC 9989 treats `p=quarantine; pct=25` as full quarantine. Receivers still built on RFC 7489 may apply the percentage, which may differ from the current-policy grade shown here. ### RFC 9989: enforcement guidance [Section 7.4](https://www.rfc-editor.org/rfc/rfc9989#section-7.4) says "domains that host users who might post messages to mailing lists SHOULD NOT publish Domain Owner Assessment Policies of "p=reject"", and domains that publish `p=reject` "MUST apply valid DKIM signatures to their messages." The tool grades `p=reject` as PASS and offers Reject as the last step of the path to enforcement without this caveat. It cannot know who sends from the domain, so weigh section 7.4 yourself before that step. [Section 5.1.7](https://www.rfc-editor.org/rfc/rfc9989#section-5.1.7) ties the move to enforcement to "many months of consuming DMARC aggregate reports" in some cases. The tool does not read reports, so it cannot judge readiness. ### RFC 9990 and RFC 9991: reports | Section | Requirement | What the tool does | | --- | --- | --- | | [RFC 9990, 3.5](https://www.rfc-editor.org/rfc/rfc9990#section-3.5) | Malformed URIs SHOULD be ignored; deliver to every remaining URI | Flags the first malformed `rua` entry as a FAIL | | [RFC 9990, 4](https://www.rfc-editor.org/rfc/rfc9990#section-4) | When the policy's Organizational Domain differs from the destination's, query `<policy-domain>._report._dmarc.<destination-host>` | Names that record for the first external address; does not look it up | | [RFC 9990, 4](https://www.rfc-editor.org/rfc/rfc9990#section-4) | The comparison is between Organizational Domains | Approximated: an address outside the checked domain and its subdomains counts as external | | [RFC 9991, 5](https://www.rfc-editor.org/rfc/rfc9991#section-5) | The same verification applies to `ruf` | Not done for `ruf` | | [RFC 9991, 2](https://www.rfc-editor.org/rfc/rfc9991#section-2) | Failure report options come from `ruf` and `fo` | Explained only | The approximation errs both ways: a report address at the parent domain of a checked subdomain is called external although it shares the Organizational Domain, and no external note is made for a pasted record. ### Alignment, SPF and DKIM DMARC passes when SPF ([RFC 7208](https://www.rfc-editor.org/rfc/rfc7208)) or DKIM ([RFC 6376](https://www.rfc-editor.org/rfc/rfc6376)) produces an authenticated identifier aligned with the From domain ([RFC 9989, section 4.4](https://www.rfc-editor.org/rfc/rfc9989#section-4.4)). The tool only reads the `adkim` and `aspf` modes and explains the difference between relaxed and strict alignment ([sections 3.2.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.10.1) and [3.2.10.2](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.10.2)). It checks no SPF record, no DKIM key and no message; use the SPF and DKIM checkers for those. ### DNS names and internationalized domains The `_dmarc` label is registered in the "Underscored and Globally Scoped DNS Node Names" registry of [RFC 8552](https://www.rfc-editor.org/rfc/rfc8552); RFC 9989 [section 9.5](https://www.rfc-editor.org/rfc/rfc9989#section-9.5) now holds that registration, and [RFC 8553](https://www.rfc-editor.org/rfc/rfc8553) updated RFC 7489 to use the registry. [RFC 8616, section 6](https://www.rfc-editor.org/rfc/rfc8616#section-6) updated RFC 7489 so that U-labels are converted to A-labels and `rua` and `ruf` hold conventional addresses; RFC 9989 section 5.3.1 carries the A-label rule. The tool converts the domain you enter to A-labels before the lookup and accepts any non-space characters around the `@` of a report address. ## Finding reference Each finding the checker can emit, grouped by what it judges, with what it means for mail sent as the domain. The RFC section column names the rule behind the finding; "none" marks a Tamperbox recommendation that the specification does not require. ### Record and tag syntax Problems that make receivers ignore the record or parts of it. Links point to RFC 9989 unless marked. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | No DMARC record (verdict) | FAIL | No policy at this name; a parent policy may apply | Publish the starting draft | [4.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.10.1) | | N DMARC records | FAIL | Receivers discard every record at the name | Delete all but one | [4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10) | | Not a DMARC record (verdict) | FAIL | Receivers ignore the whole record | Put v=DMARC1 first | [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) | | Not a tag: X | FAIL | Receivers discard the part | Write name=value | [4.8](https://www.rfc-editor.org/rfc/rfc9989#section-4.8) | | name appears twice | FAIL | The tag list is invalid; the policy is not graded | Keep one value | [RFC 6376, 3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2) | | name=value is not valid | FAIL | Bad `p`, `sp` or `np`: `p=none` if `rua` is valid, else no DMARC; bad `adkim` or `aspf`: default `r` | Use a valid value | [4.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-4.10.1), [4.8](https://www.rfc-editor.org/rfc/rfc9989#section-4.8) | | No p= policy: defaults to none | INFO | Receivers act as if `p=none` | Add p=none | [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) | | pct=X is obsolete | CHECK | Current receivers ignore percentage sampling | Remove pct | [A.6](https://www.rfc-editor.org/rfc/rfc9989#appendix-A.6) | | Invalid report address X | FAIL | Receivers skip that address | Use mailto: | [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) | | Unknown tag X | CHECK | Receivers ignore it | Review or remove it | [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) | ### Policy strength How much of the failing mail the policy acts on. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | p=none only monitors | CHECK | Spoofed mail is still delivered | Move to quarantine when reports are clean | none (Tamperbox recommendation); [3.2.12](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.12) defines the mode | | DMARC test mode (t=y) | CHECK | Effective policy is one level below the declared policy | Review reports before disabling test mode | [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) | | sp=none on subdomains | CHECK | Subdomains can be spoofed | Remove sp or match p | none (Tamperbox recommendation); [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) defines `sp` | | p=reject, p=quarantine | PASS | Failing mail is refused or quarantined | | [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) | ### Reports and alignment Who receives aggregate reports and how strictly identities must match. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | No rua reports | CHECK | You cannot see who sends as the domain | Add rua=mailto:… | none (Tamperbox recommendation); [4.7](https://www.rfc-editor.org/rfc/rfc9989#section-4.7) makes `rua` optional | | Reports go to X | INFO | The receiving domain must authorise the reports | Publish the authorisation record there | [RFC 9990, 4](https://www.rfc-editor.org/rfc/rfc9990#section-4) | | Strict alignment | INFO | Subdomain-signed or subdomain-bounced mail fails | Relaxed is usually enough | [3.2.10.2](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.10.2) | | N report addresses | PASS | Aggregate reports are on | | [4.6](https://www.rfc-editor.org/rfc/rfc9989#section-4.6) | ## Guide ### From p=none to reject 1. Make sure `rua` points at a mailbox or a reporting service you read. Raw aggregate reports are XML; a parsing service makes them readable. 2. Read a few weeks of reports. List every source that sends as the domain: your mail host, newsletter tool, ticketing, invoicing, and anything you forgot. 3. Make each one pass SPF or DKIM with a domain aligned with the From domain. Check their records with the SPF and DKIM checkers. 4. Choose Test quarantine, review the draft `p=quarantine; t=y`, and publish it only after checking receiver compatibility. Current receivers treat this as monitoring. Remove test mode to request quarantine after reviewing legitimate mail. 5. When the reports stay clean, move to Quarantine all, then Reject, the same way. ### No DMARC record Publish the starting draft shown on the page, `v=DMARC1; p=none; rua=mailto:dmarc@<domain>`, at `_dmarc.<domain>` as a TXT record. Then follow the rollout above. ### Two records at the _dmarc name A provider migration usually leaves the old record beside the new one. Delete every record but one, then check the domain again. ### A misspelt policy, a missing p, a bad percentage Heal it offers the exact repair: the closest valid policy for a misspelling, `p=none` for a missing policy, removing obsolete `pct`. Each repair is a draft; copy and publish it. ### Report addresses Write each address as `mailto:name@domain`; separate several with commas. If the reports go to a domain other than yours (a reporting service), that domain must publish `<yourdomain>._report._dmarc.<their-domain>`; the service's documentation says what to publish, and the INFO finding names the record. ### Subdomains Leave `sp` unset so subdomains follow `p`, or set it to the same policy. `sp=none` on an enforcing domain leaves every subdomain open to spoofing. ### Break it cases Each case is built from the record you entered or looked up. | Case | What it does to your record | Heal it offers | | --- | --- | --- | | No policy | Removes `p=` | Add p=none | | Policy typo | Misspells the policy (`rejected`, `quarantined`, `nnone`) | Change p=… to the valid value | | Version not first | Moves `v=DMARC1` after the first tag | Put corrected v=DMARC1 first | | Bad report address | Strips `mailto:` from rua | Make rua a mailto: address | | Invalid test mode | Sets `t=invalid` | Disable invalid test mode | | Duplicate tag | Adds a second, conflicting `p=` | Keep p=none, Keep p=reject | ## Worked example The page opens on a live check of `tamperbox.dev`. Its published records and findings can change over time. For the deterministic walkthrough below, enter `harbor-supply.example`. This reserved `.example` domain is answered from synthetic data in your browser; it sends no live lookup. Its record: ```text v=DMARC1; p=none; rua=mailto:dmarc@harbor-supply.example; ruf=mailto:forensics@harbor-supply.example; fo=1 ``` **Monitoring only: no DMARC enforcement requested.** The findings are "p=none only monitors" (CHECK, with a button to the next step) and "1 report address" (PASS). Choose Test quarantine: the draft becomes `v=DMARC1; p=quarantine; t=y; rua=…; ruf=…; fo=1`, History logs the change with Revert, and the record to publish shows the draft at `_dmarc.harbor-supply.example`. Replace the sample with your own domain and every section, card and link is rewritten for it. ## For agents The Tamperbox MCP server runs the same checks. Search its catalog for the DMARC operation, inspect the input schema, and call it with the domain or the record. Keep the warning block with any conclusion: - The tool grades the policy text; whether legitimate mail passes is in the aggregate reports. - Parent policy is discovered through a bounded DNS tree walk; inherited `np` applicability is not verified because domain existence is not checked. - External report authorisation records are named, not looked up. - The `pct` tag is obsolete and does not reduce the effective policy. The `t` tag controls test mode. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the domain travels. ## Limits - The policy, not the reports: enforcement readiness is not assessed. - Parent policy is discovered through a bounded DNS tree walk; inherited `np` applicability is not verified because domain existence is not checked. - `ruf`, `fo`, `rf` and `ri` are explained, not validated. - The tag table recognizes `t` and `psd`; legacy `rf` and `ri` explanations remain and are not flagged as removed. - One DNS answer, from one public resolver, at one moment. - Nothing is stored; copying a draft does not publish it. ## References ### DMARC - [RFC 9989, Domain-Based Message Authentication, Reporting, and Conformance (DMARC)](https://www.rfc-editor.org/rfc/rfc9989), Proposed Standard, May 2026. Obsoletes RFC 7489 and RFC 9091. Sections used: 3.2.10 (alignment), 3.2.12 (Monitoring Mode), 3.2.13 (non-existent domains), 4.4 (identifier alignment), 4.5 (the record in DNS), 4.6 (reporting URIs), 4.7 (tags), 4.8 (formal definition), 4.10 and 4.10.1 (DNS tree walk and policy discovery), 5.1.5 and 5.1.7 (Domain Owner actions), 5.3.1 (A-labels), 7.4 (interoperability and `p=reject`), 9.5 (`_dmarc` registration), appendices A.6 (removal of `pct`) and C.5 (tag changes). - [RFC 9990, DMARC Aggregate Reporting](https://www.rfc-editor.org/rfc/rfc9990), Proposed Standard, May 2026. Obsoletes RFC 7489 in part. Sections used: 3.5 (report delivery) and 4 (verifying external destinations). - [RFC 9991, DMARC Failure Reporting](https://www.rfc-editor.org/rfc/rfc9991), Proposed Standard, May 2026. Obsoletes RFC 7489 in part and updates RFC 6591. Sections used: 2 (failure reports, `ruf` and `fo`) and 5 (verifying external destinations). - [RFC 7489, DMARC](https://www.rfc-editor.org/rfc/rfc7489), Informational, March 2015. Obsoleted by RFC 9989, RFC 9990 and RFC 9991. Cited only as the source of the `pct`, `rf` and `ri` tags the tool still knows. ### Authentication and DNS - [RFC 7208, Sender Policy Framework](https://www.rfc-editor.org/rfc/rfc7208), Proposed Standard, updated by RFC 8616 and RFC 8553. Cited for the SPF identifier that DMARC aligns; not checked by this tool. - [RFC 6376, DomainKeys Identified Mail Signatures](https://www.rfc-editor.org/rfc/rfc6376), Internet Standard, updated by RFC 8301, RFC 8463, RFC 8553 and RFC 8616. Section 3.2 (tag lists and duplicate tags). - [RFC 8616, Email Authentication for Internationalized Mail](https://www.rfc-editor.org/rfc/rfc8616), Proposed Standard. Section 6 (DMARC and A-labels). - [RFC 8552, Scoped Interpretation of DNS Resource Records through "Underscored" Naming of Attribute Leaves](https://www.rfc-editor.org/rfc/rfc8552), Best Current Practice 222. The registry that holds `_dmarc`. - [RFC 8553, DNS AttrLeaf Changes: Fixing Specifications That Use Underscored Node Names](https://www.rfc-editor.org/rfc/rfc8553), Best Current Practice 222. Section 2.1 (TXT RRsets, which lists RFC 7489). ### Tamperbox - Tamperbox guide: [DMARC rollout: from p=none to reject](https://tamperbox.dev/guides/dmarc-monitoring-to-reject) --- # DNS Lookup How the DNS Lookup asks a public resolver or a zone's own nameserver for one record type, how it checks the response, what every status, flag and finding means, and how to confirm a fix with dig. Canonical: https://docs.tamperbox.dev/tools/dns-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A DNS name, or a dig answer or zone file lines to paste Outputs: A verdict for the answer with status, DNSSEC and TTL chips, findings, the answer and authority sections, the response flags in words, and the answer as dig-style text Limitations: One answer from one resolver at one moment; the AD flag is the resolver's assertion and is not re-verified; the authoritative path does not validate DNSSEC The tool page is [tamperbox.dev/dns-lookup](https://tamperbox.dev/dns-lookup). It opens on a live lookup of `tamperbox.dev`: a real resolver, real timing and a real DNSSEC flag. This page is the long version: what is sent, how the response is checked, what each status, flag and finding means, and how to confirm a change from your own terminal. <div class="tb-callout"><strong>Where processing happens:</strong> a name is sent to the Tamperbox server, which sends one DNS query to the resolver you pick over DNS over HTTPS, or to the zone's own nameserver over TCP port 53, and returns the decoded response. Pasted records are parsed in your browser and never uploaded. Names under the reserved <code>.example</code> zone are answered in the browser from sample data. Ordinary lookup results are not persisted by this page. An explicit handoff temporarily stores its value in session storage for one-use transfer.</div> ## What the tool answers A DNS lookup asks one question: the records of one type at one name, in one class (IN). The tool answers, in this order: 1. **Does the name exist?** The response code says NOERROR, NXDOMAIN (no such name), SERVFAIL (the resolver could not answer) or another failure. 2. **Does it hold records of this type?** NOERROR with an empty answer is NODATA: the name exists, but not with this type. 3. **Through which aliases?** Every CNAME step the resolver followed comes back in the answer section, in order. 4. **For how long will the answer be cached?** The TTL of each record, which on a recursive resolver is the time left in its cache. 5. **Was it validated?** The AD flag says the resolver authenticated the answer with DNSSEC. It does not tell you what every resolver in the world returns (that is the [DNS Propagation Checker](https://tamperbox.dev/dns-propagation)), whether the DNSSEC chain is sound link by link (that is the [DNSSEC Checker](https://tamperbox.dev/dnssec-checker)), or whether a server at the address answers. ## Inputs ### A name `example.com`, `www.example.com`, `_dmarc.example.com`. The record type is picked with the chips in the rail (A, AAAA, CNAME, MX, TXT, NS, SOA, SRV, CAA, PTR, DS, DNSKEY, TLSA) and the server with the Ask menu: Cloudflare (1.1.1.1), Google (8.8.8.8), Quad9 (9.9.9.9), or the authoritative nameserver. The lookup runs when you stop typing, about 600 ms after the last key, or at once on Enter. Changing the type or the server reruns it. Before anything is sent, the name is checked in the browser and again on the server. On the server it must be at most 253 characters, with labels of up to 63 letters, digits, hyphens or underscores and no hyphen at either end of a label. Underscores are allowed so that `_dmarc` and `_443._tcp` names can be asked. An internationalised name is converted to its ASCII form by the URL parser before it is sent. ### A pasted address or email address A pasted `https://www.example.com/pricing` becomes `www.example.com` in the box, and a pasted `someone@example.com` becomes `example.com`, through the same paste cleanup every Tamperbox tool uses. The hint under the box names what was kept. Text that does not reduce to a name stays exactly as pasted, so the error explains it. Typing is never rewritten. ### A pasted answer Text that starts with `;;`, or holds a line such as `www.example.com. 300 IN A 192.0.2.10`, is read in the browser instead of being looked up. Comments after `;` are dropped, the TTL and the class may come in either order, and only known record types are kept. The parser also reads `status:`, the `flags:` list, the question line and `Query time`, so a pasted answer is judged by the same status rules. DNSSEC findings are not produced for pasted text: the page cannot know what the original resolver verified. ### Files Drop a `.txt` file anywhere on the page, or use the drop zone. It is read in the browser. ## Reading the result ### Verdict and chips The verdict names the outcome: "2 A records for example.com", "No MX record at example.com", "NXDOMAIN: example.com does not exist", "SERVFAIL: the resolver could not answer", or "Dangling alias". The line under it says who answered and how fast. The chips are the response code, whether the answer was DNSSEC-validated, and the lowest TTL of the records asked for; each scrolls to the section it describes. ### Where your input goes Two items beside the verdict: pasted records stay in the browser; a name means one DNS query from our server. They are true for every input on this page. ### Findings Every rule that applied, worst first. Two or more passes fold into one "checks passed" line. ### Answer, Response, Authority, DNS response The answer table lists every record with its owner, TTL, type and data, aliases first. Response spells out the status and each flag that is set in words. Authority appears when the answer is empty: it usually holds the zone's SOA, which also sets how long the empty answer is cached. DNS response is the whole answer as dig-style text, with a copy button for a ticket. ### History and Heal it Break it and Heal it replace the input; History records each change with what it replaced, Revert undoes the newest, and Reset input returns to what you entered. Heal it offers to ask the authoritative server after a SERVFAIL, and to raise a pasted TTL under 60 seconds to one hour. ### Take it further Links that carry a value from this answer into another tool: the first address to the ASN Lookup and to Reverse DNS, a name with A records to the propagation check, an unvalidated or failing zone to the DNSSEC Checker, and a TXT answer that holds an SPF record to the SPF Checker. Each one opens the other tool with the value already in its box; the input stays out of the URL; a temporary random fragment identifies a one-use transfer held in session storage. ## Method ### 1. The query The server builds one DNS message ([RFC 1035 section 4.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1)): a random 16-bit ID, the question (name, type, class IN), and an EDNS OPT record with a UDP payload size of 1232 bytes and the DO bit set, so that a resolver includes DNSSEC data and reports validation. For a public resolver the RD (recursion desired) bit is set and the message is sent as wire-format DNS over HTTPS: a POST to the resolver's DoH endpoint with `content-type: application/dns-message` ([RFC 8484 section 4.1](https://www.rfc-editor.org/rfc/rfc8484#section-4.1)). Redirects are not followed. ### 2. The response must answer this question A response is accepted only when all of these hold; otherwise the lookup fails with a message instead of a result: - the reply is served with the `application/dns-message` content type, or the resolver "did not return a DNS response"; - it is at most 65,535 bytes and decodes completely, with no bytes left over; - it is a response, carries the same ID, has exactly one question, and that question matches the name, type and class IN asked; - the TC (truncated) flag is clear. A truncated message is refused with "The DNS response was truncated", because a partial answer would look complete. The ID and question checks follow the matching rule in [RFC 1035 section 7.3](https://www.rfc-editor.org/rfc/rfc1035#section-7.3): a resolver should check that a response matches a query it sent before using it. ### 3. Asking the authoritative nameserver Choosing "Authoritative · TCP 53" skips caches: 1. The zone is found from the SOA record that Cloudflare returns with checking disabled (CD set), taking the longest zone name that contains the name asked. 2. The zone's NS records are read the same way; up to four nameservers are taken, and up to four public IPv4 or IPv6 addresses for each. 3. The query is sent over TCP port 53 ([RFC 1035 section 4.2.2](https://www.rfc-editor.org/rfc/rfc1035#section-4.2.2)), without recursion, to each address in turn, with a short deadline per attempt. 4. Only a reply with the AA (authoritative answer) flag is accepted. A server that answers without it is skipped, which filters out lame delegations. If nothing qualifies the result is "No discovered authoritative nameserver answered over TCP port 53." The common causes are nameservers that do not answer over TCP, a firewall dropping TCP 53, or NS records that point at servers no longer serving the zone. An authoritative server does not validate DNSSEC, which is why this is the way to see what a zone publishes when validating resolvers return SERVFAIL. ### 4. Limits on the server One lookup may spend at most 100 DNS queries (the authoritative path uses several), the whole request has an 18-second deadline, and the same question is asked once per request. Addresses that are not public are never contacted. ### 5. The verdict, by response code The response codes are those of [RFC 1035 section 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) and the registry that extends them. | Status | Records of the type | Verdict | Severity | | --- | --- | --- | --- | | NOERROR | one or more | "N TYPE records for name", with the aliases passed through | pass | | NOERROR | none | "No TYPE record at name" (NODATA) | info | | NXDOMAIN | after a CNAME | "Dangling alias: name points to target, which does not exist" | fail | | NXDOMAIN | none | "NXDOMAIN: name does not exist" | fail | | SERVFAIL | none | "SERVFAIL: the resolver could not answer" | fail | | any other | none | the code and its meaning, for example REFUSED | fail | NXDOMAIN applies to the name, not to one type: [RFC 2308 section 2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1) says that in this case "the domain referred to by the QNAME does not exist", and [RFC 8020](https://www.rfc-editor.org/rfc/rfc8020#section-2) adds that nothing exists below such a name either. NODATA ([RFC 2308 section 2.2](https://www.rfc-editor.org/rfc/rfc2308#section-2.2)) is the name existing without the type. ### 6. Findings on the answer - **More than two aliases before the answer** (check). Each CNAME step is one more lookup for a resolver that has not cached it. - **TTL under 60 seconds** (info). The lowest TTL of the records asked for. Almost every visitor reaches the authoritative servers; reasonable during a migration. - **Not validated with DNSSEC** (info). A live NOERROR answer from a public resolver without the AD flag. [RFC 4035 section 3.2.3](https://www.rfc-editor.org/rfc/rfc4035#section-3.2.3) says a security-aware resolver "MUST NOT set the AD bit in a response unless the name server considers all RRsets in the Answer and Authority sections of the response to be authentic." No AD means the zone is unsigned or this resolver did not validate it; the page cannot tell which. ### 7. TTLs and negative caching A recursive resolver returns the time left in its cache, not the TTL the zone publishes ([RFC 1034 section 3.6](https://www.rfc-editor.org/rfc/rfc1034#section-3.6), [RFC 2181 section 8](https://www.rfc-editor.org/rfc/rfc2181#section-8)); asking the authoritative server shows the published value. An empty answer is cached too: [RFC 2308 section 5](https://www.rfc-editor.org/rfc/rfc2308#section-5) takes its lifetime from the SOA in the authority section, the lower of that record's TTL and its MINIMUM field. ## Standards and conformance | Specification | Sections used | How the tool applies it | Where it stops | | --- | --- | --- | --- | | [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035) | [4.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1) message format, [4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) header and RCODE, [4.2.2](https://www.rfc-editor.org/rfc/rfc1035#section-4.2.2) TCP, [7.3](https://www.rfc-editor.org/rfc/rfc1035#section-7.3) response matching | Messages are built and decoded on the server; ID and question are matched; TCP framing uses the two-byte length prefix | Updated by many later RFCs, including RFC 2181, RFC 2308 and RFC 4035; the tool follows those where they apply | | [RFC 8484](https://www.rfc-editor.org/rfc/rfc8484) | [4.1](https://www.rfc-editor.org/rfc/rfc8484#section-4.1) POST requests | Wire-format POST with the DNS message media type to each resolver's DoH endpoint | Uses POST only; the GET form, which suits HTTP caches, is not used | | [RFC 6891](https://www.rfc-editor.org/rfc/rfc6891) | [6.1.2](https://www.rfc-editor.org/rfc/rfc6891#section-6.1.2) OPT record | One OPT record with a 1232-byte payload size and the DO bit | EDNS options and extended RCODEs are not shown | | [RFC 4035](https://www.rfc-editor.org/rfc/rfc4035) | [3.2.3](https://www.rfc-editor.org/rfc/rfc4035#section-3.2.3) the AD bit | The AD flag is reported as the resolver's validation result | Signatures are not checked locally; the DNSSEC Checker reads the chain | | [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308) | [2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1), [2.2](https://www.rfc-editor.org/rfc/rfc2308#section-2.2), [5](https://www.rfc-editor.org/rfc/rfc2308#section-5) | NXDOMAIN and NODATA are told apart; the authority SOA is shown | The negative TTL is explained, not computed per resolver | | [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034) | [3.6](https://www.rfc-editor.org/rfc/rfc1034#section-3.6), [3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2) aliases | CNAME steps are listed before the answer; a chain ending in NXDOMAIN is a dangling alias | Chains are followed by the resolver, not by the tool | ## Finding reference | Finding | Severity | Source | What it means for whoever relies on the name | Fix | | --- | --- | --- | --- | --- | | N TYPE records answered | pass | [RFC 1035 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) | The name resolves to these records until their TTL runs out | None | | No TYPE record at name | info | [RFC 2308 2.2](https://www.rfc-editor.org/rfc/rfc2308#section-2.2) | The name exists but has nothing of this type; anything expecting it gets nothing | Add the record if something needs it | | The name does not exist | fail | [RFC 2308 2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1) | Every lookup of the name fails at once, and the failure is cached | Fix the spelling, or add the record in the zone that holds the parent | | Dangling alias | fail | [RFC 1034 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2) | The alias points at a name that is gone; whoever claims it can serve content on yours | Remove the CNAME or recreate the target | | The resolver could not answer | fail | [RFC 1035 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) | Visitors behind validating resolvers cannot reach the name | Ask the authoritative server; check the DNSSEC chain | | Another code from the server | fail | [RFC 1035 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) | The server refused or could not process the question | Depends on the code; REFUSED often means the server is not authoritative for the zone | | N aliases before the answer | check | [RFC 1034 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2) | Slower first lookups and more places for the chain to break | Point the first name closer to the end | | TTL of under a minute | info | [RFC 2181 8](https://www.rfc-editor.org/rfc/rfc2181#section-8) | Nearly every visitor queries the authoritative servers | Raise the TTL after the change settles | | Not validated with DNSSEC | info | [RFC 4035 3.2.3](https://www.rfc-editor.org/rfc/rfc4035#section-3.2.3) | The answer was not authenticated; a validating client cannot tell it from a forged one | Sign the zone and publish the DS record at the registrar | ## Guide ### A record you just changed still shows the old value 1. Ask the authoritative server on this page. If it shows the new value, the change is published and resolvers are holding the old answer until its TTL runs out. 2. Read the TTL on a public resolver: that is the most it can keep the old answer. 3. Run the [DNS Propagation Checker](https://tamperbox.dev/dns-propagation) to see which public resolvers still differ. 4. Next time, lower the TTL to a few minutes a day before the change. Confirm from a terminal: `dig +norecurse @<one of the zone's nameservers> www.example.com A` shows the published answer, and `dig @1.1.1.1 www.example.com A` shows Cloudflare's cache. ### NXDOMAIN for a name you expect Check the spelling and the zone: a record added to `example.com` as `www.example.com.example.com` (a missing final dot in a zone file) is a classic cause. If the name was created minutes ago, the negative answer may still be cached for up to the zone's negative TTL, the last field of its SOA. `dig example.com SOA` shows it. ### SERVFAIL Use Heal it: "Ask the authoritative server". If the zone's own server answers, the zone is up and validating resolvers reject it, which almost always means a broken DNSSEC chain: a DS record at the registrar that matches no key the zone publishes, or expired signatures. Confirm with `dig +cd @1.1.1.1 example.com A`: with checking disabled the resolver returns the answer it otherwise rejects. Then open the zone in the [DNSSEC Checker](https://tamperbox.dev/dnssec-checker). ### A dangling alias Remove the CNAME, or recreate the target at the service it pointed to. Then look for others: every alias to a service you no longer use is a candidate. The [CNAME Lookup](https://tamperbox.dev/cname-lookup) draws the chain step by step. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | Name does not exist | `nohost.` in front of your name | NXDOMAIN and the negative-caching note | | Broken DNSSEC | a sample zone whose DS matches no key | SERVFAIL, and Heal it asking the authoritative server | | Dangling alias | a sample alias to a deleted host | NXDOMAIN after a CNAME | | Very short TTL | your own answer, pasted back with a TTL of 30 seconds | The short-TTL finding, and Heal it raising it to an hour | ## Worked example The page opens on `tamperbox.dev`, type A, asked of Cloudflare. It is a live lookup, so the addresses, TTLs and timing are whatever Cloudflare returns at that moment; the shape of the result is what this example is for. The verdict names the A records and says Cloudflare answered, with its time. The chips show NOERROR, the DNSSEC state and the lowest TTL. If the response lacks AD, Findings reports “Not validated with DNSSEC”; that flag alone does not establish whether the zone is unsigned. Available handoffs depend on the current answer, record type and flags. Switch the type to AAAA and the same name returns its IPv6 addresses; switch the server to Authoritative and the TTLs become the published ones. ## For agents The Tamperbox MCP server exposes the same lookup as the `dns_lookup` operation, with `name`, `type` and `resolver` (the three public resolvers, nine more, or `authoritative`). It returns the question, status, flags, answer and authority. Keep these warnings with any conclusion: - The AD flag is the resolver's assertion, not a local validation. - One answer from one resolver at one moment; other caches may differ until the TTL expires. - An empty answer (NODATA) is not the same as NXDOMAIN or a resolver failure. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern. ## Limits - One resolver's view at one moment; a public resolver answers from its cache. - The AD flag is reported, not re-verified. The authoritative path does not validate DNSSEC at all. - A record that resolves is publication evidence: it does not prove a server answers at the address. - Pasted answers are read as text; the page cannot know whether DNS serves them today. - Sample names under `.example` are answered in the browser from fixed data, labelled as the sample zone. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034): Domain names, concepts and facilities. Sections 3.6, 3.6.2. Updated by many, including RFC 2181, RFC 2308, RFC 4035 and RFC 8020. - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035): Domain names, implementation and specification. Sections 4.1, 4.1.1, 4.2.2, 7.3. - [RFC 2181](https://www.rfc-editor.org/rfc/rfc2181): Clarifications to the DNS specification. Section 8, TTLs. - [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308): Negative caching of DNS queries. Sections 2.1, 2.2, 5. - [RFC 4035](https://www.rfc-editor.org/rfc/rfc4035): DNSSEC protocol modifications. Section 3.2.3, the AD bit. - [RFC 6891](https://www.rfc-editor.org/rfc/rfc6891): Extension mechanisms for DNS (EDNS(0)). Section 6.1.2. - [RFC 8020](https://www.rfc-editor.org/rfc/rfc8020): NXDOMAIN, there really is nothing underneath. Section 2. - [RFC 8484](https://www.rfc-editor.org/rfc/rfc8484): DNS queries over HTTPS (DoH). Section 4.1. --- # DNS Propagation Checker How the DNS Propagation Checker asks twelve public resolvers and the zone's own nameserver the same question, compares every answer with the authoritative one, what a different answer, an error or a SERVFAIL means, and how to make the next change reach everyone faster. Canonical: https://docs.tamperbox.dev/tools/dns-propagation/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A DNS name Outputs: A verdict counting the resolvers that agree with the zone, findings, an agreement bar, one row per server with its answer, cache time, status and response time Limitations: Thirteen observations from our server at one moment; anycast resolvers answer from the site nearest to our server; a TTL is a maximum, not a deadline; the visitor's own ISP resolver is not asked The tool page is [tamperbox.dev/dns-propagation](https://tamperbox.dev/dns-propagation). It opens on `harbor-supply.example`, a sample domain on the reserved `.example` zone whose address changed forty minutes ago while three resolvers still hold the old one. This page is the long version: what "propagation" really is, how the answers are compared, the findings, and how to plan a change that reaches everyone quickly. <div class="tb-callout"><strong>Where processing happens:</strong> a name is sent to the Tamperbox server, which asks twelve public resolvers over DNS over HTTPS and the zone's own nameserver over TCP port 53 the same question, at the same time, and returns every answer. The comparison is drawn in your browser. Sample names under <code>.example</code> are answered in the browser. Ordinary lookup results are not persisted by this page. An explicit handoff temporarily stores its value in session storage for one-use transfer.</div> ## What the tool answers DNS changes do not travel anywhere. The zone's nameservers answer with the new data at once; what lags are the caches of recursive resolvers, each of which keeps the old answer until its TTL runs out ([RFC 1034 section 3.6](https://www.rfc-editor.org/rfc/rfc1034#section-3.6): "The meaning of the TTL field is a time limit on how long an RR can be kept in a cache."). "Propagation" is those caches expiring. The tool answers: 1. **What does the zone publish now?** The authoritative answer, the source of truth. 2. **Which public resolvers already return it?** Each one compared with the source. 3. **Which differ, and what TTLs do they report?** The answer each one holds and the TTL left on it. 4. **Is something worse than caching going on?** Errors, different statuses, or every resolver failing at once. It cannot clear a cache, and it does not ask the resolver at a visitor's own internet provider. ## Inputs ### A name `example.com`, `www.example.com`. Pick the record type in the rail: A, AAAA, CNAME, MX, TXT or NS. The check runs when you stop typing, or on Enter; Check again repeats it. A pasted address or email address is reduced to its host or domain. Pasted records are not accepted: the point is to ask the resolvers. ## Reading the result ### Verdict and chips "Propagated: all 12 resolvers return 192.0.2.10." when every public answer matches the zone; "9 of 12 resolvers return 192.0.2.10." when some differ, with the largest TTL among them; "NXDOMAIN everywhere:" when every resolver agrees the name does not exist; "Resolvers return SERVFAIL:" when the zone answers and no public resolver does; "Source unavailable:" when the zone's own nameserver could not be asked. The chips count the agreeing resolvers, give the largest TTL still held, and count failures. ### Where your input goes The comparison is drawn in the browser; a name starts twelve public-resolver observations and one authoritative observation. Finding the authoritative zone and a reachable server can require additional SOA, NS and address queries, so thirteen observations are not a thirteen-packet limit. ### Findings Failures and checks first, then the different answers, then the pass counting the matching resolvers. ### Agreement One bar split by answer: solid for the resolvers that match the zone, hatched for those holding a different answer, marked for failures. Under it, each distinct answer with how many resolvers return it. ### Every resolver One row per server, the zone's own first: its name, address and where it answers from; its answer (and error, if any); "Cached for", the largest TTL among the compared records; a status badge (Source, Matches, Differs, the DNS status, Lookup failed, or Not compared); and its response time. ### History and Heal it History logs Break it and Heal it replacements. Revert restores the previous input; Reset input restores the first input in that sequence. Restoring a live name runs a fresh lookup. Typing starts a new history, and the log is not a monitoring record. ### Take it further The authoritative address to the ASN Lookup and to Reverse DNS, and, when every public resolver returns SERVFAIL while the source answers, the name to the DNSSEC Checker. ## Method ### 1. The servers asked | Resolver | Address | Where | | --- | --- | --- | | Cloudflare | 1.1.1.1 | Anycast | | Google Public DNS | 8.8.8.8 | Anycast | | Quad9 | 9.9.9.9 | Anycast, Switzerland | | OpenDNS (Cisco) | 208.67.222.222 | Anycast, United States | | AdGuard DNS | 94.140.14.14 | Anycast, Cyprus | | Control D | 76.76.2.0 | Anycast, Canada | | Mullvad DNS | 194.242.2.2 | Sweden | | DNS.SB | 185.222.222.222 | Germany | | NextDNS | 45.90.28.0 | Anycast | | CleanBrowsing | 185.228.168.9 | Anycast, United States | | AliDNS | 223.5.5.5 | China | | Yandex DNS | 77.88.8.8 | Russia | Each is asked over DNS over HTTPS with a wire-format POST ([RFC 8484 section 4.1](https://www.rfc-editor.org/rfc/rfc8484#section-4.1)), with recursion desired and an EDNS record asking for DNSSEC data. Each response must match the question and must not be truncated, as on the DNS Lookup. The zone's own nameserver is found and asked over TCP port 53 exactly as the DNS Lookup's authoritative option does: the zone from its SOA, up to four NS hosts, up to four public addresses each, and only a reply with the AA flag counts. Every server has its own deadline (5 seconds for a public resolver, 14 for the authoritative search), so one slow server cannot discard the others' answers; a server that fails is shown as "Lookup failed" with its reason. ### 2. One comparable value per server For each server the page builds one value: the records of the type asked, sorted and joined; or the status when it is not NOERROR; or "No record" when the answer is empty. When the zone answers with an alias, the comparison is of that CNAME, not of whatever the resolvers' chains lead to, so an answer that differs only further down the chain is not counted as different. "Cached for" is the largest TTL among the compared records. ### 3. Matching A public answer matches when neither it nor the source failed, its status equals the source's and its value equals the source's. Every non-match is either: - **a different answer**: status NOERROR, no error, a different value. Caching, geo-routing and provider filtering are possible causes; - **a failure**: an error, or a different status (SERVFAIL, NXDOMAIN while the zone says NOERROR, and so on). ### 4. Findings and verdict | Situation | Finding | Severity | Verdict | | --- | --- | --- | --- | | The zone's own nameserver failed | Authoritative answer unavailable | check | Source unavailable (check) | | The zone answers, every public resolver returns SERVFAIL | Every public resolver returns SERVFAIL | fail | Resolvers return SERVFAIL (fail) | | Some resolvers hold a different answer | N resolvers returned a different answer | info | N of M resolvers return value (check) | | Some resolvers fail, not all | N resolvers returned an error or a different DNS status | check | N of M resolvers (check) | | Resolvers match the zone | N of M resolvers match the authoritative answer | pass | Propagated, or "STATUS everywhere" | A different answer is informational evidence of disagreement, not proof of an old cache. The largest observed TTL describes the returned records; it is not a convergence deadline. Ordinary cache expiry is defined by [RFC 1035 section 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1). Two things can stretch it: [RFC 8767 section 4](https://www.rfc-editor.org/rfc/rfc8767#section-4) lets a resolver keep using an expired record "as though it is unexpired" when it cannot refresh it, and authoritative servers that tailor answers to the resolver's location ([RFC 7871 section 1](https://www.rfc-editor.org/rfc/rfc7871#section-1)) give different answers that never converge. ### 5. Negative answers are cached too When the name did not exist before the change, resolvers that asked earlier cached the NXDOMAIN for the zone's negative TTL ([RFC 2308 section 5](https://www.rfc-editor.org/rfc/rfc2308#section-5)): "the minimum of the SOA.MINIMUM field and SOA's TTL". They show the old status until it runs out. ## Standards and conformance | Specification | Sections used | How the tool applies it | Where it stops | | --- | --- | --- | --- | | [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034) | [3.6](https://www.rfc-editor.org/rfc/rfc1034#section-3.6) | Differences retain their observed TTL; their cause is not inferred | | | [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035) | [3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1), [4.2.2](https://www.rfc-editor.org/rfc/rfc1035#section-4.2.2) | The TTL each resolver reports; the authoritative query over TCP | TTL definition amended by RFC 8767 | | [RFC 2181](https://www.rfc-editor.org/rfc/rfc2181) | [8](https://www.rfc-editor.org/rfc/rfc2181#section-8) | TTLs are read as unsigned seconds | | | [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308) | [5](https://www.rfc-editor.org/rfc/rfc2308#section-5) | A cached NXDOMAIN is explained in the guide | Negative TTLs are not computed per resolver | | [RFC 8767](https://www.rfc-editor.org/rfc/rfc8767) | [4](https://www.rfc-editor.org/rfc/rfc8767#section-4) | Explains answers held past their TTL | Stale serving cannot be detected from outside | | [RFC 8484](https://www.rfc-editor.org/rfc/rfc8484) | [4.1](https://www.rfc-editor.org/rfc/rfc8484#section-4.1) | Every public resolver is asked over DoH | Plain DNS on port 53 to resolvers is not used | ## Finding reference | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | N of M resolvers match the authoritative answer | pass | [RFC 1034 3.6](https://www.rfc-editor.org/rfc/rfc1034#section-3.6) | Those caches hold the current answer | None | | N resolvers returned a different answer | info | [RFC 1035 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1) | Those resolvers returned different data; caching, routing or filtering may explain it | Wait; lower the TTL before the next change | | N resolvers returned an error or a different DNS status | check | | Those resolvers cannot answer, or disagree on whether the name exists | Check again; persistent failure suggests filtering or an unreachable zone | | Every public resolver returns SERVFAIL | fail | [RFC 4035 3.2.3](https://www.rfc-editor.org/rfc/rfc4035#section-3.2.3) | Public resolution failed while the authoritative observation succeeded | Investigate DNSSEC and authoritative reachability | | Authoritative answer unavailable | check | [RFC 1035 4.2.2](https://www.rfc-editor.org/rfc/rfc1035#section-4.2.2) | Public answers could not be compared with the source | Check again; make the nameservers answer over TCP | ## Guide ### Plan a change that reaches everyone fast 1. A day before (or at least one old TTL before), lower the TTL of the records you will change to 300 seconds. 2. Make the change. 3. Repeat the comparison after the intended TTL interval. Investigate persistent differences rather than assuming every resolver must converge on the same answer. 4. Keep the old server running until the longest original TTL has passed, for caches that do not honour the lowered value. 5. Raise the TTL again. ### Some resolvers still show the old answer Read "Cached for" as the TTL observed in that response. Wait a reasonable interval and Check again; stale serving or intentional routing can outlast that TTL. A resolver that keeps a different answer long after is likely geo-routing or filtering rather than caching; compare with `dig @<resolver address> www.example.com A`. ### Every resolver returns SERVFAIL The authoritative observation succeeds while the public resolvers return SERVFAIL. A broken DNSSEC chain, such as a stale DS record, is one possible cause; this pattern alone does not diagnose it. Open the name in the [DNSSEC Checker](https://tamperbox.dev/dnssec-checker). `dig +cd @1.1.1.1 example.com A` (checking disabled) can help distinguish validation failure from other resolver errors; compare it with a normal query. ### Source unavailable The zone's own nameservers did not answer over TCP port 53 within the deadline. Resolvers fall back to TCP for large answers, so nameservers should answer it; ask your provider. The public answers are still shown. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | An alias | `www.harbor-supply.example`, which is a CNAME | The comparison made on the alias | | Name does not exist | `nohost.` in front of your name | "NXDOMAIN everywhere" | | Broken DNSSEC | a sample zone whose DS matches no key | "Resolvers return SERVFAIL", and the DNSSEC link | ## Worked example `harbor-supply.example`, type A. The zone's own nameserver answers `203.0.113.80`, the new address. Nine public resolvers return it too. OpenDNS, AliDNS and Yandex DNS still return `192.0.2.10`, the address before the change, with 21, 37 and 50 minutes left on their caches. The verdict reads "9 of 12 resolvers return 203.0.113.80." with "Largest observed TTL: 50 minutes 20 seconds." Findings reports the three different answers as information and folds the nine matches. The example illustrates disagreement after a change. Its largest TTL is an observation, not a promise that every real resolver will converge within an hour. Press "Broken DNSSEC" to see the all-SERVFAIL pattern, which no amount of waiting fixes. ## For agents The Tamperbox MCP server exposes `dns_propagation` with a `name` and a `type` (any type the DNS Lookup supports, not only the six chips here). It returns every resolver's raw result; the comparison described on this page is the agent's to make. Keep these warnings with any conclusion: - A sample across supported resolvers, not proof that every cache worldwide has updated. - Anycast resolvers answer from the site nearest to our server. - A TTL is a maximum, and resolvers may serve stale data past it. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/). ## Limits - Thirteen answers from our server at one moment. - Anycast: a visitor elsewhere may reach a different site of the same resolver. - The visitor's own internet provider's resolver is not asked. - TTLs are reported by each resolver and are a maximum, not a deadline. - Sample names under `.example` are answered in the browser. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034): section 3.6, resource records and the TTL. - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035): sections 3.2.1 (TTL), 4.2.2 (TCP). TTL definition amended by RFC 8767. - [RFC 2181](https://www.rfc-editor.org/rfc/rfc2181): section 8, TTLs. - [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308): section 5, caching negative answers. - [RFC 4035](https://www.rfc-editor.org/rfc/rfc4035): section 3.2.3, the AD bit and validation. - [RFC 7871](https://www.rfc-editor.org/rfc/rfc7871): client subnet in DNS queries. Section 1. - [RFC 8484](https://www.rfc-editor.org/rfc/rfc8484): DNS queries over HTTPS. Section 4.1. - [RFC 8767](https://www.rfc-editor.org/rfc/rfc8767): serving stale data to improve DNS resiliency. Section 4. --- # DNS Provider Lookup How Tamperbox groups authoritative nameservers, recognises providers, and flags fragile or mixed delegation. Canonical: https://docs.tamperbox.dev/tools/dns-provider/ Updated: 2026-10-25 Applies to: tamperbox.dev, October 2026 Prerequisites: a domain name or pasted NS records Outputs: provider groups, nameserver evidence, self-hosting clues and delegation findings Limitations: Public observations are time-sensitive and do not prove ownership, intent or private configuration The tool page is [tamperbox.dev/dns-provider](https://tamperbox.dev/dns-provider). It opens with a live lookup of `google.com`; replace it to inspect your own target. This guide documents the actual input path, evidence contract, classifications and independent verification steps. <div class="tb-callout"><strong>Where processing happens:</strong> input cleanup, pasted-data parsing and report rendering happen in the browser. Live checks send only the validated public target to the Tamperbox server and the public services required for the lookup. The page stores no report; History is local to the current browser session.</div> ## What the tool answers The checker answers which organisations appear to operate the nameservers published for a zone and whether the set is redundant or mixed. Its conclusion is deliberately narrower than an ownership or security claim. A displayed provider, product, name or passing check means that the listed public evidence matched a documented rule at the observation time. Every conclusion is paired with evidence. The opening verdict is a summary for orientation, while Findings contains the actionable interpretation and the later result sections retain the underlying records, addresses, fields or names. If a conclusion matters operationally, verify that evidence through an authoritative account or an independent standards-aware client before changing production. ## Inputs ### Accepted source Enter a domain for a live NS lookup, or paste nameserver hostnames or NS records for local classification. Multiple lines, an `IN NS` record, or names beginning with forms such as `ns1`, `dns1` or `name.ns.` select record mode. A single hostname that does not match those patterns is treated as a domain to look up. Pasted NS records can supply an owner name for the self-hosting comparison. Text files are read in the browser. The resulting input follows the same classification rules as the field; reading a file locally does not make a domain or public-IP lookup offline. Cleanup keeps an already accepted record intact and otherwise tries unwrapping a single-line address. Unusable text remains visible for correction. ### When work runs Domain input runs after a 600-millisecond typing pause. Enter runs it immediately; pasted records run immediately. Drops and page-wide paste use the same input loader. Leaving the field applies cleanup and reruns only when cleanup changes the text. Each edit aborts the previous request and increments a generation marker. A slower old response therefore cannot replace a newer result, and clearing the source immediately clears copyable output. The opening input uses the same parser and processing path as a replacement. The labelled live default sends the same requests as another domain. ## Reading the result ### Verdict and privacy The verdict states what the available evidence supports and uses pass, check, fail or informational status consistently. Pass means the bounded rule succeeded. Check means a human should confirm context. Fail means a concrete operational rule was violated. Info describes a limitation, absence or neutral fact and must not be promoted into success or failure by an automated reader. Two privacy lines distinguish browser-only work from live lookup work. The Checked line names the cleaned input and source mode. Copy result is hidden while work is pending, after an error and when input is empty, preventing a stale report from being exported as current. ### Findings and evidence Findings are ordered with failures first, then checks, informational notes and passes. Repeated passing details can fold into a disclosure so that exceptions remain visible. Each item states the observation and its consequence; any remediation is scoped to the evidence rather than presented as a universal configuration recipe. Evidence sections follow Findings and precede History. They are the audit trail for the verdict. A provider label derived from a catalog remains an inference, while a literal record or response field remains an observation. This distinction matters when signatures are incomplete, white-labelled or stale. ### History and handoffs History records intentional input replacements, including Break it examples and their repairs. Revert restores the prior input and runs it again, including live requests when applicable; Reset input returns to the value at the beginning of the recorded sequence. History is not monitoring, persistence or an account log. Check the rest carries the current input to other tools in Domains & hosting. Take it further uses the identified zone or suggested parent for [SOA](https://docs.tamperbox.dev/tools/soa-lookup/) and [DNSSEC](https://docs.tamperbox.dev/tools/dnssec-checker/) checks, and the first nameserver hostname for a [DNS lookup](https://docs.tamperbox.dev/tools/dns-lookup/). A parent inferred from the hostname is only a suggestion; SOA-derived zone evidence is labelled separately. Pasted NS records remain local until you choose a server-lookup handoff. Each receiving tool runs its own check; agreement is not guaranteed. Explicit tool links transfer the input through temporary browser `sessionStorage` and, when needed, a same-origin browser channel. The URL fragment contains a random transfer token, not the input. Transfers are accepted for less than one minute, consumed once, and bound to the destination path. The destination removes the token from its address. Ordinary documentation links and direct visits do not restore a previous input; if transfer storage is unavailable, the link still opens the tool. ## Method ### Validation and collection Before collection, the same domain validation runs in the browser and on the server boundary. Requests are restricted to supported public DNS names and HTTPS roots, redirects are bounded, response sizes are capped and abort signals are propagated. These limits make the observation reproducible and prevent an entered value from becoming an unrestricted network fetch. Use the input modes above to determine which requests run. DNS evidence comes from a public recursive view and can reflect cache state. Local classification cannot add observations absent from the supplied evidence. A server lookup is a fresh observation, not confirmation that cached or pasted evidence is still current. ### Classification rules The tool asks for NS at the entered name, normalises unique hostnames and maps their suffixes against a maintained provider catalog. If no NS exists at that owner it offers the enclosing zone. Self-hosting is inferred when nameserver names sit inside the checked zone. [RFC 1034 section 4.3.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.3.2) defines referrals and authoritative data; the tool reports the observed set but does not perform a full delegation trace. No confidence percentage is invented. When sources disagree, the disagreement is a finding. When a source is unavailable, the affected conclusion becomes informational or inconclusive rather than silently using a previous result. Catalog matches are exact bounded rules; unknown is a valid outcome. ### Ordering and export The renderer calculates all findings from the current observation before updating the verdict, chips, evidence and landing cards. Status priority is fail, check, info, pass. Stable secondary ordering keeps repeated runs readable without changing severity. The Markdown mirror and Copy result output preserve input, summary, findings and important evidence in text form. They do not embed secrets, browser state or the expanded educational cards. Agents should cite the observation time and limitation alongside any exported conclusion. ## Standards and conformance ### Applied specifications | Source | Rule used | Boundary | | --- | --- | --- | | [RFC 1034 section 4.2.1](https://www.rfc-editor.org/rfc/rfc1034#section-4.2.1) | Zones are served by authoritative name servers | The page reads NS publication from one resolver | | [RFC 1035 section 3.3.11](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.11) | NS identifies an authoritative host | Hostnames are grouped after normalisation | | [RFC 1034 section 4.2.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.2.2) | Delegations can require address glue | Self-hosted names trigger a glue reminder, not a glue audit | | [RFC 2182 section 5](https://www.rfc-editor.org/rfc/rfc2182#section-5) | Multiple secondary servers improve reliability | A single server is a failure | These references define the records and message semantics, not the provider catalogs. A catalog is product logic and can lag branding, acquisitions or custom deployments. Where a standard permits several valid configurations, the tool reports the observed form and avoids declaring one commercial pattern universally correct. ### Where conformance stops The checker is an observer, not an authoritative DNS server, browser, certificate monitor, mail receiver or provider control plane. It does not claim protocol conformance for the target. It applies selected validation and interpretation rules to bounded evidence and exposes the boundary where a fuller protocol operation would begin. The phrase “public” refers to the server's Internet view. Private split-horizon answers, authenticated dashboards and regional routing can differ. Cached answers can remain until TTL expiry, and HTTP intermediaries can transform what the origin sent. ## Finding reference ### Emitted findings | Finding | Severity | Meaning | Repair or next check | | --- | --- | --- | --- | | One nameserver | Fail | One published authority is a single point of failure | Add an independently reachable authoritative server | | Multiple providers | Check | Hostnames map to more than one provider | Confirm deliberate secondary DNS or complete migration | | Self-hosted DNS | Info | Nameservers are below the zone they serve | Confirm registrar glue and resilient networks | | Recognised provider | Pass | All names map to one catalogued operator | Verify the zone exists in that provider account | | Provider not in catalog | Info | Ownership cannot be named from suffix rules | Inspect RDAP and provider documentation | | No NS records here | Info | The name is probably below a zone apex | Look up the enclosing authoritative zone | Wording can include the observed name, count, provider or status. Automated consumers should use the supplied status and evidence rather than parsing the English title as a permanent identifier. A missing finding is not evidence that the corresponding external condition is absent when its source could not be collected. ### Status handling | Status | Consumer action | What not to infer | | --- | --- | --- | | Pass | Preserve the evidence and continue normal review | Permanent correctness, ownership or availability | | Check | Confirm intent and inspect the named evidence | Definite compromise or outage | | Fail | Prioritise the concrete broken rule and verify independently | That every user sees the same failure | | Info | Carry the limitation or neutral fact with the report | Success merely because no failure was emitted | ## Guide ### Verify independently Start with an authoritative or widely used command-line client. For DNS, use `dig` with the exact record type and compare every returned owner, target and TTL. Add `+trace` only when delegation matters; a trace and a recursive answer solve different questions. For HTTPS, use `curl -I --location https://host/` and retain each hop and response field. For certificates, use an established TLS client and a CT monitor you trust. Repeat from another network when geography or split routing could matter. Save the observation time and the original evidence before editing. After a DNS change, wait at least the prior TTL and then query both the intended authorities and independent recursive resolvers. ### Repair safely Do not delete an unfamiliar record or reroute a public name merely because a catalog labels it. First identify the owning service, deployment repository or provider account. Confirm whether the item is current, a migration remnant, a failover path or a delegated responsibility. Make the smallest reversible change, keep the prior value, and have a rollback trigger. Re-run this page after propagation, then verify the user-visible service. A clean public lookup cannot prove application health. Conversely, an informational unknown does not require a speculative change. ### Diagnose conflicting evidence When two signals disagree, ask whether they describe different layers: apex versus www, resolver cache versus authority, CDN edge versus origin, entered host versus redirected host, or certificate history versus current DNS. Compare literal evidence before comparing labels. The disagreement itself often reveals a migration or intermediary. If a lookup fails, preserve the error and retry once. Repeated timeouts are not equivalent to empty data. Use the specialist tool linked by the finding for deeper parsing rather than converting an inconclusive aggregate result into a failure. ### Break it and heal it A pasted record may include an owner name. That owner helps interpret self-hosted nameservers, but it does not turn the pasted result into a live lookup. Cards and evidence labels preserve this distinction; no DNS query is made merely because the pasted records contain a zone name. The Break it controls create documented edge cases from the visitor's own input or a reserved fixture. They are teaching states, not scans. Heal it restores a safe derived value when the repair is deterministic. Revert remains available when several changes have been made. Use these cases to learn how invalid, missing, mixed or stale evidence appears before diagnosing production. The control never edits DNS, hosting, certificates or provider accounts. ## Worked example The live default is `google.com`. Its in-zone nameserver names make the self-hosted case visible and allow the page to explain glue without pretending that a commercial DNS label is always available. Read the example from verdict to Findings, then compare the literal evidence. Open one Break it case and use Heal it or Revert. Finally, replace the default with a domain you are authorised to assess. This sequence demonstrates both the successful path and the failure contract without implying that the named public domain endorses the tool. ## For agents Agents can discover the `dns_provider` operation through Tamperbox MCP. The browser page id `dns-provider` is not the operation name. The server operation and browser renderer can expose different fields; inspect the operation schema before supplying arguments. Preserve the result's distinction between observed evidence, catalog inference and limitation. State whether the run was live or pasted, include the cleaned target and observation time, and never turn “not found” into “does not exist” unless the method truly establishes that condition. Choose a specialist operation when the task is narrow. Use this page's report when its combined view or educational findings add value. Do not pass credentials, private hostnames or customer data into a public lookup. If a repair would change production, present the exact evidence, expected effect, propagation window and rollback before acting. Machine readers should branch on status and structured fields where available, not English punctuation. Treat network and parse errors as inconclusive. Re-run after a meaningful interval rather than repeatedly polling a third-party source. ## Limits Provider inference follows hostname conventions, which can be white-labelled, resold or deliberately generic. A recursive answer may be cached. The tool does not query the parent registry, compare every authority, test geographic diversity, validate glue, transfer a zone or prove that the provider account is controlled by the domain owner. All outputs are point-in-time observations. Resolver caching, negative caching, anycast, geo steering, redirects and intermittent upstream failures can change a later run. The service does not retain a monitoring history or notify on change. Local History is an interaction aid, not durable evidence. No result grants permission to probe a target or modify it. Use authorised accounts and owner-approved procedures for deeper checks. Where business, security or legal decisions depend on attribution, obtain confirmation from the responsible provider or domain operator. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034), Domain Names — Concepts and Facilities, especially [section 4.3.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.3.2) for resolver behavior. - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035), Domain Names — Implementation and Specification, especially [section 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1) for resource-record types and classes. - [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110), HTTP Semantics, especially [section 3.7](https://www.rfc-editor.org/rfc/rfc9110#section-3.7) for intermediaries and [section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) for status codes when HTTP evidence is collected. - [Tamperbox DNS Provider Lookup](https://tamperbox.dev/dns-provider), the interactive tool and current Markdown mirror. --- # DNSSEC Checker How the DNSSEC Checker asks a validating resolver for its verdict, walks the chain of trust from the root, links every DS record to the key it names, and what each finding means for the people trying to reach a domain. Canonical: https://docs.tamperbox.dev/tools/dnssec-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain, or DS and DNSKEY records copied from a registrar or DNS provider Outputs: The resolver's verdict, one level per zone cut from the root with its DS, keys and signature windows, findings worst first, and the underlying chain evidence Limitations: Signatures are not verified and DS digests are not recomputed by the tool; only the validating resolver's AD flag reflects real verification, and only the signatures over each DNSKEY set are read The tool page is [tamperbox.dev/dnssec-checker](https://tamperbox.dev/dnssec-checker). It opens with a live lookup of `tamperbox.dev` and takes a domain, or the DS and DNSKEY records you are about to submit to a registrar. This page is the long version: what the verdict rests on, every rule applied to the chain, what each finding means, and how to fix and confirm each one. <div class="tb-callout"><strong>Where processing happens:</strong> a domain is sent to the Tamperbox server, which asks a public validating resolver for the verdict and fetches the DS, DNSKEY and RRSIG records at each zone cut, then returns them. Key tags, matching and dates are worked out in your browser. Pasted records never leave the browser. History stays in memory in the open page. Explicit links to another tool may temporarily keep a one-use transfer in browser session storage; transfers expire after one minute and do not put the input in the URL.</div> ## What the tool answers DNSSEC signs DNS answers and links the signatures in a chain: the root key signs the root zone, the root zone publishes a DS record that names the key of each top-level domain, that zone publishes a DS for each signed child, and so on down to your domain. A validating resolver follows the chain and refuses answers it cannot authenticate. The tool answers, in this order: 1. **Does a validating resolver accept this domain's answers?** Secure, bogus, insecure or not determined, from the resolver itself. 2. **Where is the chain broken?** One level per zone cut from the root, with the DS each parent publishes and the key it names. 3. **Are the keys and digests current?** Algorithms and DS digest types are judged against the current registry guidance. 4. **Are the signatures in date?** Each signature over a key set is drawn as a window with today marked. 5. **Do the records I am about to publish fit together?** For pasted DS and DNSKEY records, without any lookup. It does not verify signatures itself, does not check NSEC or NSEC3 denial of existence, and says nothing about the website or mail servers behind the domain. ## Inputs ### A domain `example.com`, or any name below it such as `www.example.com`. The check runs when you stop typing (or at once on Enter). Before it is checked the text is trimmed, and a pasted address is reduced to what the tool takes: `https://www.example.com/shop` becomes `www.example.com`, an email address becomes its domain, quotes and brackets are dropped. Text that does not contain a usable name stays exactly as pasted and the page says why it cannot be checked. Typing is never rewritten mid-word, and Break it loads are never cleaned. The walk starts from the zone that owns the name, which the server finds from the SOA record. Entering `www.example.com` therefore inspects the chain to `example.com` unless `www` is a zone of its own; the result names the zone it reached. ### Pasted DS and DNSKEY records Lines in zone-file form, as a registrar or DNS provider shows them: ```text example.com. 86400 IN DS 24895 13 2 1477FBEC43638AB9EB3D8B16270AD69FEB1B47FDFC2DB088488128D4C465D7CB example.com. 3600 IN DNSKEY 257 3 13 0YH3/nP+RGM16vLuNROUFyS/hkPzXCGa0aGCR+MctF07f+XgfGQGKADzfa5zZ026JGpYYFAe11QAU8BW1mUe8A== ``` Any text containing a DS, DNSKEY or RRSIG line is treated as records and read entirely in the browser, as one level named after the first owner name in it. At least one DS or DNSKEY line is required; otherwise the page asks for them. RRSIG lines are optional; when present their dates are judged too. This is the quick way to confirm that the DS your registrar is about to publish names the key your DNS provider signs with. ### Files Drop a text file on the page, or open one with Add a file: it is read in the browser like pasted text, up to 256 KiB, and never uploaded. ## Reading the result ### Verdict and chips The verdict line states the outcome: Secure, Bogus, Not signed, Not determined, Unsafe DNSSEC algorithm, or, for pasted records, whether they fit together. The line under it says what that means for users. The chips name each level of the chain with its state, root first; each one scrolls to that level. ### Findings Every check, worst first: failures, then things to check, then information. Passing checks are retained and folded into an expandable group when there are several. When the chain has more than one level, each finding starts with its level (`example: DS 41657 matches a key`). The count on the right is problems and things to check. The [finding reference](#finding-reference) lists every finding. ### Chain of trust One block per zone cut, from the root down. Each block shows: - **DS at the parent**: each DS record with its key tag, algorithm and digest type, and an arrow to the key it names, or "no such key". The root shows the trust anchor that validators carry built in instead. - **Keys**: each DNSKEY with its computed key tag, whether it is a key-signing key (flag 257) or a zone-signing key (256), "Revoked" when the revoke bit is set, and its algorithm. - **Signatures**: each RRSIG read with the keys, drawn as a bar from inception to expiration with today marked, labelled with the key tag that made it and the days left. ### History and next checks History appears below the result evidence after Break it or Heal it changes the input. Revert restores the input before the latest recorded change; Reset input returns to the input before the first recorded change. Typing or pasting a new input starts a new history. Restoring a live input runs the lookup again, rather than restoring a saved response. Take it further can open the registry record for the derived zone, DANE for a secure zone, or a domain health report. Pasted records offer only the registry lookup when an owner name is available. ## Method ### 1. The resolver's verdict For a domain, the server first asks Cloudflare's public resolver (1.1.1.1, DNS over HTTPS) for the name's SOA record with the DNSSEC OK bit set ([RFC 4035, section 3.2.1](https://www.rfc-editor.org/rfc/rfc4035#section-3.2.1)), and classifies the reply into the four states of [RFC 4035, section 4.3](https://www.rfc-editor.org/rfc/rfc4035#section-4.3): | Reply | State | Shown as | | --- | --- | --- | | AD flag set, NOERROR or NXDOMAIN | Secure | "Secure: signed from the root to …" | | SERVFAIL, and the same question with checking disabled (CD) succeeds | Bogus | "Bogus: …" | | NOERROR or NXDOMAIN without AD | Insecure | "Not signed", or the two variants below when the zone has keys | | Anything else, including SERVFAIL that persists with CD | Indeterminate | "Not determined" | The AD flag carries the resolver's own validation. [RFC 4035, section 3.2.3](https://www.rfc-editor.org/rfc/rfc4035#section-3.2.3) says the server side "MUST NOT set the AD bit in a response unless the name server considers all RRsets in the Answer and Authority sections of the response to be authentic". Bogus rests on [section 5.5](https://www.rfc-editor.org/rfc/rfc4035#section-5.5): when no signature validates, a recursive server "MUST return RCODE 2" (SERVFAIL) unless the query set CD, so a SERVFAIL that disappears with CD is the signature of a validation failure. A SERVFAIL that persists with CD can arise from resolver, network or authoritative-server failures, so the page reports it as not determined and says it does not establish that the zone is unsigned or broken. For an insecure answer with a deprecated key algorithm, the page says "Unsafe DNSSEC algorithm" and explains that the resolver did not validate the answer. With other published keys it says "Signed, but not validated"; without keys it says "Not signed". An insecure answer alone is not proof that no DNSKEY exists. Read the chain findings for a missing DS or deprecated algorithm. ### 2. Walking the chain The server finds the zone that owns the name from the SOA record, then visits the root and every parent label down to that zone, skipping labels that are not zone cuts (no SOA of their own), with a limit of 16 labels. At each level it fetches the DS set from the parent, the DNSKEY set and the RRSIG records over the DNSKEY set, all with checking disabled so that a broken zone can still be inspected. The root has no DS; it is shown as the trust anchor. Everything from here on is a structural reading done in the browser. The tool does not verify RRSIG signatures and does not recompute DS digests; that is the resolver's job, and its answer is the verdict above. ### 3. Key tags and flags Each DNSKEY's key tag is computed with the checksum of [RFC 4034, Appendix B](https://www.rfc-editor.org/rfc/rfc4034#appendix-B) over the flags, protocol, algorithm and key bytes. The flags are decoded per [RFC 4034, section 2.1.1](https://www.rfc-editor.org/rfc/rfc4034#section-2.1.1): bit 7 (value 256) is the zone key flag, bit 15 (value 1) the secure entry point (SEP). A key with both set (257) is shown as a key-signing key, one with only the zone flag (256) as a zone-signing key. Bit 8 (value 128) is the revoke flag of [RFC 5011, section 7](https://www.rfc-editor.org/rfc/rfc5011#section-7) and is shown as "Revoked". The display uses the SEP bit alone for its key-signing label; this does not enforce the zone-key bit or protocol value. A revoked key does not count toward the missing-key-signing-key check. The checksum helper does not implement the historical algorithm-1 key-tag exception. ### 4. Linking DS to keys [RFC 4035, section 5.2](https://www.rfc-editor.org/rfc/rfc4035#section-5.2) authenticates a delegation when "the Algorithm and Key Tag in the DS RR match the Algorithm field and the key tag of a DNSKEY RR in the child zone's apex DNSKEY RRset" and the digest matches. The tool applies the first half of that rule at every level below the root: - **DS N matches a key** (PASS) when a published DNSKEY has the same key tag and algorithm. - **DS N matches no key** (FAIL) when none does. This DS cannot identify a displayed key. Another supported DS and valid key may still authenticate the delegation; use the resolver result to assess validation. - **DS at the parent, but no keys** (FAIL) when the parent publishes a DS and the zone publishes no DNSKEY at all. - **Signed, but no DS at the parent** (CHECK) when the zone has keys and the parent publishes no DS: the chain is never connected and validators treat the zone as unsigned. - **Not signed** (INFO) when there is neither. - **No key-signing key** (CHECK) when no non-revoked key has the SEP flag. RFC 4034 section 2.1.1 says the SEP bit is "only intended to be a hint" and validators "MUST NOT alter their behavior" because of it, so this is a hygiene note, not a failure: some signers use one key for everything. The digest is shown but not recomputed, so a DS with the right tag and algorithm and a wrong digest passes this step; the resolver's bogus verdict is what exposes it. ### 5. Algorithms and digests [RFC 9904](https://www.rfc-editor.org/rfc/rfc9904) moved the canonical algorithm guidance from RFC 8624 (which it obsoletes) to the [IANA DNS Security Algorithm Numbers](https://www.iana.org/assignments/dns-sec-alg-numbers) and [DS Digest Algorithms](https://www.iana.org/assignments/ds-rr-types) registries. [RFC 9905, section 2](https://www.rfc-editor.org/rfc/rfc9905#section-2) then deprecated SHA-1: RSASHA1 and RSASHA1-NSEC3-SHA1 "MUST NOT be used when creating DNSKEY and RRSIG records", and operators of validating resolvers "MUST treat DNSSEC signing algorithms RSASHA1 and RSASHA1-NSEC3-SHA1 as unsupported, rendering responses insecure". The tool's table: | Algorithm | Name | Finding | | --- | --- | --- | | 5, 7 | RSA/SHA-1, RSA/SHA-1 (NSEC3) | FAIL: "Algorithm N: RSA/SHA-1", fix: roll to 13 | | 3, 6 | DSA/SHA-1 | FAIL | | 12 | GOST R 34.10-2001 | FAIL | | 8 | RSA/SHA-256 | none, shown by name | | 10 | RSA/SHA-512 | none | | 13 | ECDSA P-256/SHA-256 | none (recommended) | | 14 | ECDSA P-384/SHA-384 | none | | 15 | Ed25519 | none | | 16 | Ed448 | none | Numbers outside the table are shown as "algorithm N" without a judgement. A DS with digest type 1 (SHA-1) gives "DS N uses a SHA-1 digest" (CHECK); types 2 (SHA-256, [RFC 4509](https://www.rfc-editor.org/rfc/rfc4509)) and 4 (SHA-384, [RFC 6605](https://www.rfc-editor.org/rfc/rfc6605)) pass. A deprecated algorithm produces a failure-level verdict even when the resolver validated the answer. That is a policy weakness, not a claim that validation disagrees, and the verdict says so. When a deprecated algorithm and a structural failure occur together, both appear in "Unsafe DNSSEC algorithm and record issues". ### 6. Signature windows [RFC 4034, section 3.1.5](https://www.rfc-editor.org/rfc/rfc4034#section-3.1.5): an RRSIG "MUST NOT be used for authentication prior to the inception date and MUST NOT be used for authentication after the expiration date" ([RFC 4035, section 5.3.1](https://www.rfc-editor.org/rfc/rfc4035#section-5.3.1) repeats the check for validators). For every signature read: | Window | Finding | | --- | --- | | Expiration before now | FAIL: "Signature over DNSKEY expired N days ago" | | Inception after now | FAIL: "Signature over DNSKEY is not valid yet" (check the signer's clock) | | Expires in less than 3 days | CHECK: "Signature over DNSKEY expires in N days" | | Otherwise | no finding; the bar shows the window | ### 7. Resolver and records disagree The verdict and the chain come from separate queries, so during a key rollover they can see different cache states. When the resolver says secure and the records show a structural failure (and no deprecated algorithm), the verdict is "Resolver validation and record checks disagree" at CHECK level, naming the finding. ### 8. Pasted records Pasted records go through steps 3 to 6 as one level. There is no resolver, so the verdict says whether the records fit together ("The records fit together", "Broken link", "Not signed", or "Unsafe DNSSEC algorithm") and always adds that whether the signatures verify needs a validating resolver. ## Standards and conformance | Specification | Sections used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 4033](https://www.rfc-editor.org/rfc/rfc4033), DNS security introduction | [Section 2](https://www.rfc-editor.org/rfc/rfc4033#section-2) (terms: chain of trust, island of security) | Vocabulary for the result | | | [RFC 4034](https://www.rfc-editor.org/rfc/rfc4034), resource records | 2.1.1 flags, 3.1.5 signature dates, 5.1 DS fields, Appendix B key tag | Parsed and computed in the browser | Signatures and digests are not computed | | [RFC 4035](https://www.rfc-editor.org/rfc/rfc4035), protocol | 3.2.1 DO, 3.2.2 CD, 3.2.3 AD, 4.3 security states, 5.2 referrals, 5.3.1 RRSIG validity, 5.5 SERVFAIL | The verdict maps the resolver's reply to the four states; the DS rule applies the tag and algorithm half of 5.2 | Full validation is the resolver's; the tool reads RRSIGs over DNSKEY sets only | | [RFC 5011](https://www.rfc-editor.org/rfc/rfc5011) | [Section 7](https://www.rfc-editor.org/rfc/rfc5011#section-7), the REVOKE bit | Revoked keys are marked and not counted as key-signing keys | Trust anchor rollover itself is not followed | | [RFC 9904](https://www.rfc-editor.org/rfc/rfc9904) and the IANA registries | Algorithm and digest guidance (obsoletes RFC 8624) | Algorithms 3, 5, 6, 7, 12 fail | Ed448 and private algorithms are shown without a judgement | | [RFC 9905](https://www.rfc-editor.org/rfc/rfc9905) | [Section 2](https://www.rfc-editor.org/rfc/rfc9905#section-2), SHA-1 deprecated (updates RFC 4034 and RFC 5155) | RSA/SHA-1 DNSKEY algorithms produce failure findings | The DS algorithm field and its digest-type field are distinct; this RFC deprecates signing algorithms 5 and 7 | The tool reports DS digest type 1 as CHECK. That is a separate rule from RFC 9905's treatment of DS records naming signing algorithms 5 and 7. A resolver can authenticate through another supported chain; an obsolete or mismatched record does not by itself prove that every validation path fails. ## Finding reference ### Resolver and delegation | Finding | Severity | Source | What it means for people reaching the domain | Fix | | --- | --- | --- | --- | --- | | Secure: signed from the root to … | PASS | [RFC 4035 4.3](https://www.rfc-editor.org/rfc/rfc4035#section-4.3) | Validating resolvers authenticate the answers | Keep the DS in step with key changes | | Bogus: … | FAIL | [RFC 4035 5.5](https://www.rfc-editor.org/rfc/rfc4035#section-5.5) | Users behind validating resolvers cannot resolve the domain at all | See [a bogus zone](#a-bogus-zone) | | Not signed | INFO | [RFC 4035 4.3](https://www.rfc-editor.org/rfc/rfc4035#section-4.3) | Answers are not validated; no protection, no outage | Sign the zone and publish the DS | | Not determined | CHECK | [RFC 4035 4.3](https://www.rfc-editor.org/rfc/rfc4035#section-4.3) | The resolver could not finish; nothing is established | Check again; look at the nameservers | | DS N matches a key | PASS | [RFC 4035 5.2](https://www.rfc-editor.org/rfc/rfc4035#section-5.2) | The parent vouches for a published key | | | DS N matches no key | FAIL | [RFC 4035 5.2](https://www.rfc-editor.org/rfc/rfc4035#section-5.2) | This DS has no displayed matching key; another DS may validate | Confirm the resolver result and rollover state | | DS at the parent, but no keys | FAIL | [RFC 4035 5.2](https://www.rfc-editor.org/rfc/rfc4035#section-5.2) | The zone is bogus for validators | Remove the DS, or enable signing first | | Signed, but no DS at the parent | CHECK | [RFC 4033 2](https://www.rfc-editor.org/rfc/rfc4033#section-2) (island of security) | Treated as unsigned | Add the DS at the registrar | ### Algorithms and signatures | Finding | Severity | Source | What it means for people reaching the domain | Fix | | --- | --- | --- | --- | --- | | DS N uses a SHA-1 digest | CHECK | [DS digest registry](https://www.iana.org/assignments/ds-rr-types) | Validators may ignore this DS | Publish a SHA-256 DS (type 2) | | Algorithm N: name (3, 5, 6, 7, 12) | FAIL | [RFC 9905 2](https://www.rfc-editor.org/rfc/rfc9905#section-2), IANA registry | Validators drop support; the zone becomes unsigned for them | Roll to algorithm 13 | | No key-signing key | CHECK | [RFC 4034 2.1.1](https://www.rfc-editor.org/rfc/rfc4034#section-2.1.1) | Usually nothing; confirm the DS names a real key | Compare DS and keys | | Signature over DNSKEY expired … | FAIL | [RFC 4034 3.1.5](https://www.rfc-editor.org/rfc/rfc4034#section-3.1.5) | Answers fail validation | Restart re-signing | | Signature over DNSKEY is not valid yet | FAIL | [RFC 4034 3.1.5](https://www.rfc-editor.org/rfc/rfc4034#section-3.1.5) | Answers fail validation | Fix the signer's clock | | Signature over DNSKEY expires … (less than 3 days) | CHECK | [RFC 4035 5.3.1](https://www.rfc-editor.org/rfc/rfc4035#section-5.3.1) | Fails soon unless renewed | Confirm re-signing runs | | Unsafe DNSSEC algorithm (verdict) | FAIL | [RFC 9905 2](https://www.rfc-editor.org/rfc/rfc9905#section-2) | As the algorithm finding | Roll to algorithm 13 | | Resolver validation and record checks disagree (verdict) | CHECK | | Two fetches saw different states, usually mid-rollover | Check again after the TTLs | ## Guide ### A bogus zone A bogus zone is an outage for everyone behind a validating resolver, which today includes most mobile networks and the large public resolvers. 1. Read the level that fails in the chain. "DS N matches no key" or "DS at the parent, but no keys" at your own zone is the usual case. 2. If you moved DNS providers or the provider stopped signing, remove the DS at your registrar. The zone becomes unsigned, which is safe; it resolves again once the parent's DS TTL (often a day or two) has passed. 3. If you want to stay signed, copy the DS (or the DNSKEY of the key-signing key) your provider shows now and replace the DS at the registrar with it. 4. Confirm: the verdict here turns Secure (or Not signed) and the independent check below returns an answer without SERVFAIL. ### Turning DNSSEC on 1. Enable signing at your DNS provider. Prefer algorithm 13. 2. Copy the DS record it gives you, digest type 2. Paste it here together with the provider's DNSKEY: "The records fit together" means the tag and algorithm match. 3. Add the DS at your registrar. 4. Check the domain here once the registry publishes it: the chain reads Secure. ### Moving DNS providers without an outage 1. Before the move, remove the DS at the registrar and wait for the parent's DS TTL, or ask the new provider to pre-publish your keys (a multi-signer setup) if it supports it. 2. Move the nameservers. 3. Enable signing at the new provider and publish its DS. 4. Check here after each step. The dangerous state is a DS for the old provider's key above a zone served by the new provider. ### Rolling to algorithm 13 Algorithm rollovers keep both algorithms in the zone for a while. Publish and sign with the new keys first, wait for the DNSKEY TTL, then publish the new DS at the registrar, wait for the DS TTL, then remove the old DS, and only then the old keys and signatures. This page shows both algorithms during the overlap; the old one keeps failing its algorithm check until it is gone. ### Expired signatures Signatures are renewed by the signer, not by you. If they expired, find the system that signs the zone (your DNS provider, or a signer you run) and restart re-signing; if a signature starts in the future, check that machine's clock. A zone that is re-signed on schedule always shows days or weeks of window left. ### Independent check Reproduce the verdict and the records outside Tamperbox with `dig`: ```sh # The resolver's verdict: look for "ad" in the flags line, or SERVFAIL dig +dnssec SOA example.com @1.1.1.1 # The same question with checking disabled: an answer here but SERVFAIL above means bogus dig +dnssec +cd SOA example.com @1.1.1.1 # The DS at the parent and the zone's keys with their tags dig +short DS example.com @1.1.1.1 dig +multi DNSKEY example.com @1.1.1.1 ``` `dig +multi` prints each key's tag in a comment (`; KSK; alg = ECDSAP256SHA256 ; key id = 24895`), which must equal the first number of a DS. ### Break it cases The page's Break it cases are sample zones on the reserved `.example` zone, because a broken chain is a state of the world rather than an edit to your input. The pasted mismatch is built from your own records when the page has them. | Case | What it loads | What it shows | | --- | --- | --- | | DS does not match | `legacy-shop.example` | Bogus; the DS names key 4412, the zone publishes other keys | | Not signed | `harbor-blog.example` | Not signed: no keys, no DS | | Signatures expired | `old-signing.example` | Bogus; the signatures over the keys expired three days ago | | SHA-1 algorithm | `sha1-zone.example` | Unsafe DNSSEC algorithm: RSA/SHA-1 (NSEC3) | | Pasted mismatch | Your zone's DS with a key tag the zone does not publish, and its keys | Broken link: DS matches no key, read in the browser | After a break, Heal it offers "Restore input before this break", and the restored input runs again. ## Worked example The page opens by checking `tamperbox.dev` live. Read the resolver state first, then inspect the zone the SOA lookup selected and each chain level. A secure answer means this resolver validated this question at this time. It does not guarantee that another resolver has the same cached keys or that unrelated record sets are valid. Compare each DS key tag and algorithm with the displayed DNSKEY set, then inspect the signature windows. A tag match is only a structural match: the digest is not recomputed. If a secure result and a structural finding disagree, preserve both observations and repeat with an independent validating resolver before changing a delegation. Use the reserved Break it cases to inspect a mismatched DS, an unsigned zone, expired signatures or an obsolete algorithm. These fixtures are separate from the live opening. Restore your previous input through Heal it to run that target again. The live keys, signatures and outcome can change, so this guide deliberately gives no fixed key tags or expiry counts for the opening domain. ## For agents Search the Tamperbox MCP catalog for `dnssec_checker` and inspect its schema. The operation accepts the DNS name and returns the server's resolver status, AD flag and diagnostic chain levels. It does not return the browser's rendered finding list; do not present the raw chain as independent signature verification. Keep these warnings with any conclusion: - Secure, bogus and insecure are one validating resolver's answer at one moment; the chain is diagnostic. - Signatures over records other than the DNSKEY set are not read, and DS digests are not recomputed. - Not determined is not evidence that a zone is unsigned or broken. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) for the calling pattern and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the domain travels. ### Keeping an observation reproducible Record the target, the time of the lookup, the relevant raw records and the resolver or registry that supplied them. Repeat a live lookup after a configuration change instead of assuming a restored input restores an old response. A saved RDAP object or pasted DNSSEC record set is a snapshot: its dates are assessed against the current clock, but its contents are not refreshed. Separate absence from failure. A successful response with no applicable record, a rejected input, a timeout and an upstream error support different conclusions. Preserve an error when a query could not complete; do not replace it with a claim that the record does not exist. When sharing findings, include the narrow observation and the relevant limitation rather than only the verdict label. ## Limits - One validating resolver, from one place, at one moment. Caches elsewhere may still hold an older state. - Signatures are not verified and DS digests are not recomputed by the tool. - Only the signatures over each DNSKEY set are read; a lapsed signature on another record is not seen. - NSEC and NSEC3 denial of existence are not checked. - Reserved Break it fixtures use generated keys on the `.example` zone. - History stays in memory in the open page. Explicit links to another tool may temporarily keep a one-use transfer in browser session storage; transfers expire after one minute and do not put the input in the URL. ## References - [RFC 4033, DNS Security Introduction and Requirements](https://www.rfc-editor.org/rfc/rfc4033), section 2 - [RFC 4034, Resource Records for the DNS Security Extensions](https://www.rfc-editor.org/rfc/rfc4034), sections 2.1.1, 3.1.5, 5.1 and Appendix B; updated by RFC 9905 among others - [RFC 4035, Protocol Modifications for the DNS Security Extensions](https://www.rfc-editor.org/rfc/rfc4035), sections 3.2, 4.3, 5.2, 5.3.1 and 5.5 - [RFC 4509, SHA-256 in DNSSEC Delegation Signer records](https://www.rfc-editor.org/rfc/rfc4509) - [RFC 5011, Automated Updates of DNSSEC Trust Anchors](https://www.rfc-editor.org/rfc/rfc5011), section 7 - [RFC 6605, ECDSA for DNSSEC](https://www.rfc-editor.org/rfc/rfc6605) - [RFC 9904, DNSSEC Cryptographic Algorithm Recommendation Update Process](https://www.rfc-editor.org/rfc/rfc9904) (obsoletes RFC 8624) - [RFC 9905, Deprecating SHA-1 in DNSSEC Signature Algorithms](https://www.rfc-editor.org/rfc/rfc9905), section 2 - [IANA DNS Security Algorithm Numbers](https://www.iana.org/assignments/dns-sec-alg-numbers) and [DS RR Type Digest Algorithms](https://www.iana.org/assignments/ds-rr-types) --- # Domain Availability Checker How the Domain Availability Checker asks a domain's registry over RDAP whether the name is registered, reads the registration's life and status codes, and what each finding means for someone who wants the name or already owns it. Canonical: https://docs.tamperbox.dev/tools/domain-availability/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain name, or an RDAP domain record saved as JSON Outputs: Registered or not, the registration's life from creation to expiry, its status codes in plain words, findings worst first, and the registry status evidence Limitations: One registry record at one moment; reserved, premium and blocked names can be absent from RDAP and still be unavailable, and endings without an RDAP service cannot be checked The tool page is [tamperbox.dev/domain-availability](https://tamperbox.dev/domain-availability). It opens with a live lookup of `tamperbox.dev` and takes a domain or a saved RDAP record. This page is the long version: where the answer comes from, what "no registration found" does and does not prove, how each status code and date is read, and what to do next whether you want the name or own it. <div class="tb-callout"><strong>Where processing happens:</strong> a domain is sent to the Tamperbox server, which finds the registry for its ending in the IANA bootstrap list and asks that registry's RDAP service for the domain, then returns the record unchanged. The record is read in your browser. Pasted RDAP JSON never leaves the browser. History stays in memory in the open page. Explicit links to another tool may temporarily keep a one-use transfer in browser session storage; transfers expire after one minute and do not put the input in the URL.</div> ## What the tool answers 1. **Is the name registered?** Whether the registry holds a record for it. 2. **Since when, and until when?** The registration and expiry dates, drawn as one line with today marked. 3. **What holds it?** The status codes the registrar and registry set: locks, holds, grace periods, redemption. 4. **Is it about to change hands?** An expiry close at hand, a name in redemption or pending deletion, with an estimated drop date. 5. **Is the owner protected?** A missing transfer lock, and the registry lock when present. It does not register names, quote prices, or check trademarks. For the full record, including nameservers, DNSSEC data and contacts, use the [WHOIS & RDAP Lookup](https://docs.tamperbox.dev/tools/whois-lookup/). ## Inputs ### A domain `example.com`, checked when you stop typing (or at once on Enter). A pasted address is reduced to what the tool takes: `https://www.example.com/page` becomes `www.example.com`, an email address becomes its domain, quotes and brackets are dropped. Text that contains nothing usable stays as pasted with an explanation. Typing is never rewritten mid-word, and Break it loads are never cleaned. Enter the registered name itself. Registries hold records for registered domains, not for names below them, so `www.example.com` usually returns no record even when `example.com` is registered. If a subdomain has no record, enter the registered domain yourself; removing one label is not a reliable public-suffix rule. ### RDAP JSON A domain record saved from an RDAP service (it starts with `{` and has `"objectClassName": "domain"`), pasted or dropped as a file up to 256 KiB. It is read in the browser with the same rules; anything else is refused with "Not readable JSON" or "Not an RDAP domain response". ## Reading the result ### Verdict and chips "Registered: example.com is 20 years old and expires in 300 days", "Registered, expired: … expired N days ago", "Not available yet: … expired and is being released" with an estimated drop date, or "No registration found". The chips say registered or being released, when it expires, and the first status that blocks the domain; each scrolls to its section. ### Findings The lifecycle checks, worst first: expiry, holds, the transfer lock, the registry lock, an unsigned delegation. Passing checks are folded when there are several. The count reports problems and things to check, or "No problems". The [finding reference](#finding-reference) lists them all. ### Registration A line from registration to expiry with today marked (it turns amber within 30 days of expiry and red after it), then date facts: registered and how long ago, expires and how soon, last changed, and the registrar name. ### Status codes Each status the record carries, with its plain name, what it means and a badge: locks are normal protection (PASS), holds stop the domain resolving (FAIL), grace periods are information. ### History and next checks History appears below the result evidence after Break it or Heal it changes the input. Revert restores the input before the latest recorded change; Reset input returns to the input before the first recorded change. Typing or pasting a new input starts a new history. Restoring a live input runs the lookup again, rather than restoring a saved response. Take it further offers the expiry as a Unix timestamp and, when the registry reports a signed delegation, a DNSSEC check for the domain. When a longer name has no record, Heal it may offer the name one label up. This is a suggested next lookup, not a determination of the registrable domain. ## Method ### 1. Finding the registry The server reads the IANA RDAP bootstrap file for domain names and picks the service for the longest matching ending ([RFC 9224, section 4](https://www.rfc-editor.org/rfc/rfc9224#section-4)). Only HTTPS service URLs are used. An ending with no RDAP service gives "No HTTPS RDAP service is published for this name or address. This does not mean it is available." The query is `domain/<name>` under that service ([RFC 9082, section 3.1.3](https://www.rfc-editor.org/rfc/rfc9082#section-3.1.3)); up to three redirects are followed, each to a public HTTPS address. ### 2. Not found [RFC 7480, section 5.3](https://www.rfc-editor.org/rfc/rfc7480#section-5.3): a server with no data "returns a 404 (Not Found) response code. Optionally, it MAY include additional information … in the HTTP entity body." The tool treats a 404 as "no registration" only when it carries RDAP evidence: an error document with `errorCode` 404, or an empty body served as `application/rdap+json` or `application/json` (Verisign, which runs `.com` and `.net`, sends no body). The empty-body case requires a successful body read and a JSON or RDAP JSON media type, optionally with parameters. A failed body read or an HTML 404 from a gateway remains an error or inconclusive answer, not evidence of a free name. Other errors are reported as errors (rate limiting has its own message). No record gives the INFO verdict "No registration found" and an INFO finding, "No registration record". Both explain that a missing record does not guarantee availability. ### 3. Reading the record The record must be an RDAP domain object ([RFC 9083, section 5.3](https://www.rfc-editor.org/rfc/rfc9083#section-5.3)). The tool reads the registration, expiration and last-changed events ([section 4.5](https://www.rfc-editor.org/rfc/rfc9083#section-4.5)), the status values ([section 4.6](https://www.rfc-editor.org/rfc/rfc9083#section-4.6)), the registrar entity with its IANA ID, and `secureDNS.delegationSigned`. Status values are the EPP statuses of [RFC 5731, section 2.3](https://www.rfc-editor.org/rfc/rfc5731#section-2.3) and [RFC 3915, section 3.1](https://www.rfc-editor.org/rfc/rfc3915#section-3.1) as mapped into RDAP by [RFC 8056, section 2](https://www.rfc-editor.org/rfc/rfc8056#section-2) ("client transfer prohibited" for `clientTransferProhibited`); they are compared without spaces and case. ### 4. Status codes | Status | Shown as | Badge | | --- | --- | --- | | active, ok | Active | PASS | | client/server transfer, delete, update prohibited | Transfer lock, Delete lock, Update lock (Registry … for server) | PASS | | client renew prohibited | Renew lock: often a billing or dispute hold | CHECK | | client hold, server hold | On hold: the domain does not resolve | FAIL | | add, renew, auto-renew, transfer period | Just registered, Just renewed, Auto-renewed, Just transferred | INFO | | pending transfer, pending restore | Transfer pending, Restore pending | CHECK | | redemption period | Expired, redeemable | FAIL | | pending delete | Being deleted | FAIL | | inactive | No nameservers | CHECK | Unknown statuses are listed as they are, as INFO. ### 5. Lifecycle checks The findings use rounded whole days until expiry. A timestamp just past expiry can therefore still produce an "Expires" warning until rounding becomes negative; the verdict and date fields compare the timestamp directly. Applied in this order: | Check | Finding | Level | | --- | --- | --- | | Redemption period or pending delete | "Expired and on its way out" | FAIL | | Otherwise, expiry date passed | "Expired N days ago" | FAIL | | Otherwise, expiry within 30 days | "Expires in N days" | CHECK | | Otherwise, expiry known | "Expires in N days" | PASS | | Client or server hold | "On hold" | FAIL | | No transfer lock, and not pending or in redemption | "No transfer lock" | CHECK | | Server transfer and server update prohibited | "Registry lock" | PASS | | `delegationSigned` false | "Delegation not signed" | INFO | ### 6. Being released For a domain in redemption or pending delete, the verdict estimates when it could be registered again: the last change plus 35 days in redemption, or plus 5 days in pending delete. ICANN's [Expired Registration Recovery Policy](https://www.icann.org/resources/pages/errp-2013-02-28-en) requires gTLD registries to "offer a Redemption Grace Period ("RGP") of 30 days immediately following the deletion of a registration"; pending delete commonly lasts five days. These are estimates: registries differ, and country-code endings follow their own rules. ### 7. The verdict Being released ("Not available yet", CHECK) comes first; then an expired registration ("Registered, expired", CHECK); otherwise "Registered" at CHECK level when a finding needs attention and INFO otherwise. No record gives "No registration found" (INFO). ## Standards and conformance | Specification | Sections used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 7480](https://www.rfc-editor.org/rfc/rfc7480), RDAP over HTTP | [5.3](https://www.rfc-editor.org/rfc/rfc7480#section-5.3) negative answers | A 404 with RDAP evidence is no registration | An HTML 404 is not trusted as an answer, stricter than the RFC requires | | [RFC 9082](https://www.rfc-editor.org/rfc/rfc9082) (obsoletes RFC 7482), queries | [3.1.3](https://www.rfc-editor.org/rfc/rfc9082#section-3.1.3) domain path | Exact-name lookups only | No search queries | | [RFC 9083](https://www.rfc-editor.org/rfc/rfc9083) (obsoletes RFC 7483), responses | 4.5 events, 4.6 status, 5.3 domain object | Read in the browser | Remarks and notices are not shown here; WHOIS shows the raw record | | [RFC 9224](https://www.rfc-editor.org/rfc/rfc9224) (obsoletes RFC 7484), bootstrap | [4](https://www.rfc-editor.org/rfc/rfc9224#section-4) | Longest matching ending, HTTPS only | Endings without a service are reported, not guessed through WHOIS | | [RFC 5731](https://www.rfc-editor.org/rfc/rfc5731), [RFC 3915](https://www.rfc-editor.org/rfc/rfc3915), [RFC 8056](https://www.rfc-editor.org/rfc/rfc8056) | Status values and their RDAP mapping | Plain names and weights per status | | | [ICANN ERRP](https://www.icann.org/resources/pages/errp-2013-02-28-en) | Redemption Grace Period | The drop-date estimate | Country-code registries follow their own policies | ## Finding reference | Finding | Level | Source | What it means | What to do | | --- | --- | --- | --- | --- | | No registration record (finding); No registration found (verdict) | INFO | [RFC 7480 5.3](https://www.rfc-editor.org/rfc/rfc7480#section-5.3) | No record; availability unknown | [Register it](#registering-a-free-name) | | Expires in N days (more than 30) | PASS | [RFC 9083 4.5](https://www.rfc-editor.org/rfc/rfc9083#section-4.5) | Paid up | | | Expires in N days (30 or fewer) | CHECK | | Lapses soon without renewal | [Renew](#an-expiry-close-at-hand) | | Expired N days ago | FAIL | | Past the reported expiry; renewal rights depend on policy | Renew now, or wait if you want it | | Expired and on its way out | FAIL | [RFC 3915 3.1](https://www.rfc-editor.org/rfc/rfc3915#section-3.1) | Redemption or pending delete | [Restore or backorder](#a-name-being-released) | | On hold | FAIL | [RFC 5731 2.3](https://www.rfc-editor.org/rfc/rfc5731#section-2.3) | The domain does not resolve | Ask the registrar why | | No transfer lock | CHECK | [RFC 5731 2.3](https://www.rfc-editor.org/rfc/rfc5731#section-2.3) | The domain can be moved with its auth code | Turn the lock on | | Registry lock | PASS | [RFC 5731 2.3](https://www.rfc-editor.org/rfc/rfc5731#section-2.3) | Server transfer and update restrictions are present; process is registry-specific | | | Delegation not signed | INFO | [RFC 9083 5.3](https://www.rfc-editor.org/rfc/rfc9083#section-5.3) | No DS at the registry; DNSSEC is not in use | See the [DNSSEC Checker](https://docs.tamperbox.dev/tools/dnssec-checker/#turning-dnssec-on) | ## Guide ### Registering a free name 1. Search the exact name at a registrar; it confirms availability and the price (premium names cost more). 2. Register it for a year or more, with auto-renew on and the transfer lock on. 3. Check here: the record appears when the registry publishes it; an add-period status may appear. ### An expiry close at hand Turn on auto-renew at the registrar and confirm the payment card; check here after the renewal, when the expiry moves forward a year. If the registrar shows a renew lock, ask why: it is often a billing or dispute hold. ### A name being released If it is yours, ask your registrar to restore it from redemption now; the fee rises and the window closes about 30 days after deletion. If you want it, place a backorder or check here after the estimated drop date. Names in redemption do not resolve and cannot be transferred. ### Independent check ```sh # Find the RDAP service for the ending in the IANA bootstrap file, then ask it curl -s https://data.iana.org/rdap/dns.json | grep -o '"https://[^"]*verisign[^"]*com[^"]*"' | head -1 curl -s -o /dev/null -w '%{http_code}\n' https://rdap.verisign.com/com/v1/domain/example.com ``` 200 means registered; 404 means the registry has no record. ### Break it cases Every case is a sample registry record on the reserved `.example` zone, because a registration's life is a state of the world rather than an edit to your input. | Case | Name | What it shows | | --- | --- | --- | | Not registered | `harborsupply-marine.example` | No registration found | | Expires in two weeks | `dockside-tools.example` | Expiry close at hand, and no transfer lock | | Expired, redeemable | `anchor-chandlery.example` | Being released, with an estimated drop date | | Registered last week | `harbor-supply-store.example` | Just registered (add period), transfer-locked | ## Worked example The page opens with a live RDAP lookup of `tamperbox.dev`. First check whether a registration record was returned. If it was, read the creation and expiration events, then the status codes. Do not infer an exact renewal deadline from the age label or treat a reported expiry as a promise of public release. Compare the registry's events with the account at the registrar if you control the domain. Registrar billing dates and registry expiration events can differ, particularly around an auto-renew period. A server transfer restriction and an ordinary client lock are different evidence; neither supplies the private account procedure required to transfer or restore a name. Choose Expired, redeemable in Break it for a reserved example of redemption. The estimated release date illustrates the calculation, not a reservation or a guarantee that the name will be offered for registration. Heal it restores the earlier input and repeats a live lookup when appropriate. The opening registration, remaining days and statuses are intentionally not frozen in this guide. ## For agents Search the Tamperbox MCP catalog for `domain_availability`, inspect its schema, and supply `domain`. A found record returns `registered: true`, `registrable: false`, raw evidence, parsed registration and checks. A confirmed RDAP not-found response returns `registered: false` and `registrable: null`; null means availability is unknown. Other failures remain errors. Browser fixtures are not a promise of equivalent public MCP lookup results. Keep these warnings with any conclusion: - No registration record is not a guarantee of availability; a registrar confirms it. - One registry record at one moment. - Drop dates are estimates. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) for the calling pattern and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the domain travels. ### Keeping an observation reproducible Record the target, the time of the lookup, the relevant raw records and the resolver or registry that supplied them. Repeat a live lookup after a configuration change instead of assuming a restored input restores an old response. A saved RDAP object or pasted DNSSEC record set is a snapshot: its dates are assessed against the current clock, but its contents are not refreshed. Separate absence from failure. A successful response with no applicable record, a rejected input, a timeout and an upstream error support different conclusions. Preserve an error when a query could not complete; do not replace it with a claim that the record does not exist. When sharing findings, include the narrow observation and the relevant limitation rather than only the verdict label. ## Limits - One registry record, at one moment. - Reserved, premium and blocked names can be missing from RDAP and still not be available. - Endings whose registry publishes no RDAP service cannot be checked. - Drop dates after redemption are estimates. - The Break it cases use sample records on the reserved `.example` zone. - History stays in memory in the open page. Explicit links to another tool may temporarily keep a one-use transfer in browser session storage; transfers expire after one minute and do not put the input in the URL. ## References - [RFC 3915, Domain Registry Grace Period Mapping for EPP](https://www.rfc-editor.org/rfc/rfc3915), section 3.1 - [RFC 5731, EPP Domain Name Mapping](https://www.rfc-editor.org/rfc/rfc5731), section 2.3 - [RFC 7480, HTTP Usage in RDAP](https://www.rfc-editor.org/rfc/rfc7480), section 5.3 - [RFC 8056, EPP and RDAP Status Mapping](https://www.rfc-editor.org/rfc/rfc8056), section 2 - [RFC 9082, RDAP Query Format](https://www.rfc-editor.org/rfc/rfc9082), section 3.1.3 (obsoletes RFC 7482) - [RFC 9083, JSON Responses for RDAP](https://www.rfc-editor.org/rfc/rfc9083), sections 4.5, 4.6 and 5.3 (obsoletes RFC 7483) - [RFC 9224, Finding the Authoritative RDAP Service](https://www.rfc-editor.org/rfc/rfc9224), section 4 (obsoletes RFC 7484) - [ICANN Expired Registration Recovery Policy](https://www.icann.org/resources/pages/errp-2013-02-28-en) --- # Domain Health Check How Tamperbox combines DNS, mail, TLS, HTTP and security-header observations into one bounded health report. Canonical: https://docs.tamperbox.dev/tools/domain-health/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: a domain name Outputs: area summaries and individual checks for DNS, email, HTTPS and security headers with handoffs to specialist tools Limitations: Public observations are time-sensitive and do not prove ownership, intent or private configuration The tool page is [tamperbox.dev/domain-health](https://tamperbox.dev/domain-health). It opens with a live lookup of `wikipedia.org`; replace it to inspect your own target. This guide documents the actual input path, evidence contract, classifications and independent verification steps. <div class="tb-callout"><strong>Where processing happens:</strong> input cleanup and report rendering happen in the browser; there is no pasted-report mode. Live checks send only the validated public target to the Tamperbox server and the public services required for the lookup. The page stores no report; History is local to the current browser session.</div> ## What the tool answers The checker answers whether a set of public DNS, mail and HTTPS checks pass, need attention, fail or remain informational at one observation time. Its conclusion is deliberately narrower than an ownership or security claim. A displayed provider, product, name or passing check means that the listed public evidence matched a documented rule at the observation time. Every conclusion is paired with evidence. The opening verdict is a summary for orientation, while Findings contains the actionable interpretation and the later result sections retain the underlying records, addresses, fields or names. If a conclusion matters operationally, verify that evidence through an authoritative account or an independent standards-aware client before changing production. ## Inputs ### Accepted source Enter a domain name. This tool has no pasted-report mode: pasting or dropping text can supply a domain, but a valid domain always starts live checks. A pasted URL or email address can be reduced to its hostname by shared cleanup. A typed URL is initially invalid; leaving the field or pressing Enter applies cleanup. Private network targets are refused at the server boundary. Text files are read in the browser. The resulting input follows the same classification rules as the field; reading a file locally does not make a domain or public-IP lookup offline. Cleanup keeps an already accepted record intact and otherwise tries unwrapping a single-line address. Unusable text remains visible for correction. ### When work runs Domain input runs after a 600-millisecond typing pause. Enter runs it immediately; pasted records run immediately. Drops and page-wide paste use the same input loader. Leaving the field applies cleanup and reruns only when cleanup changes the text. Each edit aborts the previous request and increments a generation marker. A slower old response therefore cannot replace a newer result, and clearing the source immediately clears copyable output. The opening input uses the same parser and processing path as a replacement. The labelled live default sends the same requests as another domain. ## Reading the result ### Verdict and privacy The verdict states what the available evidence supports and uses pass, check, fail or informational status consistently. Pass means the bounded rule succeeded. Check means a human should confirm context. Fail means a concrete operational rule was violated. Info describes a limitation, absence or neutral fact and must not be promoted into success or failure by an automated reader. Two privacy lines distinguish browser-only work from live lookup work. The Checked line names the cleaned input and source mode. Copy result is hidden while work is pending, after an error and when input is empty, preventing a stale report from being exported as current. ### Findings and evidence Findings are ordered with failures first, then checks, informational notes and passes. Repeated passing details can fold into a disclosure so that exceptions remain visible. Each item states the observation and its consequence; any remediation is scoped to the evidence rather than presented as a universal configuration recipe. Evidence sections follow Findings and precede History. They are the audit trail for the verdict. A provider label derived from a catalog remains an inference, while a literal record or response field remains an observation. This distinction matters when signatures are incomplete, white-labelled or stale. ### History and handoffs History records intentional input replacements, including Break it examples and their repairs. Revert restores the prior input and runs it again, including live requests when applicable; Reset input returns to the value at the beginning of the recorded sequence. History is not monitoring, persistence or an account log. Check the rest carries the current input to other tools in Domains & hosting. Take it further is currently hidden because this page declares no derived-value recipes. A handoff starts a fresh check and must not be read as evidence that the receiving tool will agree. ## Method ### Validation and collection Before collection, the same domain validation runs in the browser and on the server boundary. Requests are restricted to supported public DNS names and HTTPS roots, redirects are bounded, response sizes are capped and abort signals are propagated. These limits make the observation reproducible and prevent an entered value from becoming an unrestricted network fetch. Use the input modes above to determine which requests run. DNS evidence comes from a public recursive view and can reflect cache state. Local classification cannot add observations absent from the supplied evidence. A server lookup is a fresh observation, not confirmation that cached or pasted evidence is still current. ### Classification rules The report runs independent DNS queries, a validating DNSSEC check, bounded SPF and DMARC parsing, TLS inspection and one HTTPS root fetch. A broken DNSSEC chain stops dependent areas because validating users cannot obtain trusted answers. Other checks continue independently and are sorted by severity inside four areas. The overall verdict counts outcomes and names the first failure or warning, never an average score. No confidence percentage is invented. When sources disagree, the disagreement is a finding. When a source is unavailable, the affected conclusion becomes informational or inconclusive rather than silently using a previous result. Catalog matches are exact bounded rules; unknown is a valid outcome. ### Ordering and export The renderer calculates all findings from the current observation before updating the verdict, chips, evidence and landing cards. Status priority is fail, check, info, pass. Stable secondary ordering keeps repeated runs readable without changing severity. The Markdown mirror and Copy result output preserve input, summary, findings and important evidence in text form. They do not embed secrets, browser state or the expanded educational cards. Agents should cite the observation time and limitation alongside any exported conclusion. ## Standards and conformance ### Applied specifications | Source | Rule used | Boundary | | --- | --- | --- | | [RFC 4033 section 3.1](https://www.rfc-editor.org/rfc/rfc4033#section-3.1) | DNSSEC authenticates DNS data and denial | A validating resolver supplies secure, insecure, bogus or indeterminate state | | [RFC 2182 section 5](https://www.rfc-editor.org/rfc/rfc2182#section-5) | Multiple authorities improve availability | One NS fails; mixed providers warn | | [RFC 7208 section 4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) | SPF DNS mechanisms have a ten-lookup limit | Static expansion reports a potential over-limit path; it does not evaluate a sender IP | | [RFC 9989 section 4.5](https://www.rfc-editor.org/rfc/rfc9989#section-4.5) | DMARC policy is published in DNS | Exact-name policy is parsed; inheritance is left to the specialist | | [RFC 8446 section 1](https://www.rfc-editor.org/rfc/rfc8446#section-1) | TLS 1.3 protects application communication | TLS 1.2 and 1.3 pass; retired versions fail | | [RFC 9110 section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) | HTTP status identifies response outcome | A 400-or-higher final response fails | These references define the records and message semantics, not the provider catalogs. A catalog is product logic and can lag branding, acquisitions or custom deployments. Where a standard permits several valid configurations, the tool reports the observed form and avoids declaring one commercial pattern universally correct. ### Where conformance stops The checker is an observer, not an authoritative DNS server, browser, certificate monitor, mail receiver or provider control plane. It does not claim protocol conformance for the target. It applies selected validation and interpretation rules to bounded evidence and exposes the boundary where a fuller protocol operation would begin. The phrase “public” refers to the server's Internet view. Private split-horizon answers, authenticated dashboards and regional routing can differ. Cached answers can remain until TTL expiry, and HTTP intermediaries can transform what the origin sent. ## Finding reference ### Emitted findings | Area and finding | Severity | Meaning | Repair or next check | | --- | --- | --- | --- | | DNSSEC signed and valid | Pass | The validation chain succeeds | Monitor rollover and expiry operationally | | DNSSEC broken | Fail | Validating resolvers return failure | Repair DS, DNSKEY or signatures first | | DNSSEC not signed/not checked/not determined | Info or check | Authentication is absent or inconclusive | Open DNSSEC Checker for the chain | | One nameserver | Fail | Delegation has one authority | Add resilient authoritative service | | Multiple DNS providers | Check | Zones may drift | Confirm intentional secondary service | | SOA timer warning | Check | A timer falls outside the tool range | Review transfer and negative-cache policy | | CAA summary | Pass or info | Exact-name issuance restrictions were read | Use CAA Lookup for inheritance | | Mail, SPF and DMARC findings | Pass, check or fail | Public mail routing and sender policy vary | Open the linked specialist before editing | | Certificate trust, expiry and TLS | Pass, check, fail or info | The observed HTTPS identity and protocol vary | Renew, fix names or modernise protocol | | HTTP and security headers | Pass, check, fail or info | The final response and defensive fields vary | Fix the normal application response | | No IPv6 | Info | Bare domain lacks AAAA | Add only after the delivery path supports it | Wording can include the observed name, count, provider or status. Automated consumers should use the supplied status and evidence rather than parsing the English title as a permanent identifier. A missing finding is not evidence that the corresponding external condition is absent when its source could not be collected. ### Status handling | Status | Consumer action | What not to infer | | --- | --- | --- | | Pass | Preserve the evidence and continue normal review | Permanent correctness, ownership or availability | | Check | Confirm intent and inspect the named evidence | Definite compromise or outage | | Fail | Prioritise the concrete broken rule and verify independently | That every user sees the same failure | | Info | Carry the limitation or neutral fact with the report | Success merely because no failure was emitted | ## Guide ### Verify independently Start with an authoritative or widely used command-line client. For DNS, use `dig` with the exact record type and compare every returned owner, target and TTL. Add `+trace` only when delegation matters; a trace and a recursive answer solve different questions. For HTTPS, use `curl -I --location https://host/` and retain each hop and response field. For certificates, use an established TLS client and a CT monitor you trust. Repeat from another network when geography or split routing could matter. Save the observation time and the original evidence before editing. After a DNS change, wait at least the prior TTL and then query both the intended authorities and independent recursive resolvers. ### Repair safely Do not delete an unfamiliar record or reroute a public name merely because a catalog labels it. First identify the owning service, deployment repository or provider account. Confirm whether the item is current, a migration remnant, a failover path or a delegated responsibility. Make the smallest reversible change, keep the prior value, and have a rollback trigger. Re-run this page after propagation, then verify the user-visible service. A clean public lookup cannot prove application health. Conversely, an informational unknown does not require a speculative change. ### Diagnose conflicting evidence When two signals disagree, ask whether they describe different layers: apex versus www, resolver cache versus authority, CDN edge versus origin, entered host versus redirected host, or certificate history versus current DNS. Compare literal evidence before comparing labels. The disagreement itself often reveals a migration or intermediary. If a lookup fails, preserve the error and retry once. Repeated timeouts are not equivalent to empty data. Use the specialist tool linked by the finding for deeper parsing rather than converting an inconclusive aggregate result into a failure. ### Break it and heal it The Break it controls create documented edge cases from the visitor's own input or a reserved fixture. They are teaching states, not scans. Heal it restores a safe derived value when the repair is deterministic. Revert remains available when several changes have been made. Use these cases to learn how invalid, missing, mixed or stale evidence appears before diagnosing production. The control never edits DNS, hosting, certificates or provider accounts. ## Worked example The live default is `wikipedia.org`. It produces meaningful checks in all four areas without deliberately opening on a failing verdict. The report changes with DNS, certificates and HTTP configuration, so the example demonstrates coverage rather than certifying Wikipedia. Read the example from verdict to Findings, then compare the literal evidence. Open one Break it case and use Heal it or Revert. Finally, replace the default with a domain you are authorised to assess. This sequence demonstrates both the successful path and the failure contract without implying that the named public domain endorses the tool. ## For agents Agents can discover the `domain_health` operation through Tamperbox MCP. The browser page id `domain-health` is not the operation name. The server operation and browser renderer can expose different fields; inspect the operation schema before supplying arguments. Preserve the result's distinction between observed evidence, catalog inference and limitation. State whether the run was live or pasted, include the cleaned target and observation time, and never turn “not found” into “does not exist” unless the method truly establishes that condition. Choose a specialist operation when the task is narrow. Use this page's report when its combined view or educational findings add value. Do not pass credentials, private hostnames or customer data into a public lookup. If a repair would change production, present the exact evidence, expected effect, propagation window and rollback before acting. Machine readers should branch on status and structured fields where available, not English punctuation. Treat network and parse errors as inconclusive. Re-run after a meaningful interval rather than repeatedly polling a third-party source. ## Limits This is a triage report, not a compliance certificate or uptime monitor. It uses public resolvers and one server-side HTTPS vantage point. It does not test every authoritative server, SMTP delivery, DKIM selectors, DMARC inheritance, every CAA ancestor, browser rendering, application authentication, vulnerability exposure or historical reliability. All outputs are point-in-time observations. Resolver caching, negative caching, anycast, geo steering, redirects and intermittent upstream failures can change a later run. The service does not retain a monitoring history or notify on change. Local History is an interaction aid, not durable evidence. No result grants permission to probe a target or modify it. Use authorised accounts and owner-approved procedures for deeper checks. Where business, security or legal decisions depend on attribution, obtain confirmation from the responsible provider or domain operator. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034), Domain Names — Concepts and Facilities, especially [section 4.3.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.3.2) for resolver behavior. - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035), Domain Names — Implementation and Specification, especially [section 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1) for resource-record types and classes. - [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110), HTTP Semantics, especially [section 3.7](https://www.rfc-editor.org/rfc/rfc9110#section-3.7) for intermediaries and [section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) for status codes when HTTP evidence is collected. - [Tamperbox Domain Health Check](https://tamperbox.dev/domain-health), the interactive tool and current Markdown mirror. --- # Email Header Analyzer How the analyzer turns raw message headers into a route with delays and TLS per hop, reads the receiver's authentication results, compares the From, Return-Path and DKIM domains, every rule it applies, what each finding means, and what to do about it. Canonical: https://docs.tamperbox.dev/tools/email-header-analyzer/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: The raw headers of a message, or an .eml file Outputs: A verdict with PASS, CHECK and FAIL chips, the route hop by hop, the authentication results and identities, the message summary, every header, and the findings Limitations: Results are what the receiving server recorded, not fresh verification; headers below your own receiver can be forged; alignment is an exact domain match; delays depend on each server's clock The tool page is [tamperbox.dev/email-header-analyzer](https://tamperbox.dev/email-header-analyzer). It opens on a working example: an order confirmation sent through a mail service, held for 38 seconds at one hop, with SPF passing for the service rather than the brand. This page is the long version: how the header block is read, every rule applied to the route, the authentication results and the identities, which parts of which standards the tool follows and where it stops, what each finding means, and what to do about it. <div class="tb-callout"><strong>Where processing happens:</strong> the whole header block is parsed in your browser and never uploaded. Only when you choose Look up hop addresses are the public IP addresses of the hops, and nothing else, sent to the Tamperbox server for public DNS and network registry lookups. Nothing is stored.</div> ## What the tool answers Every server that handles a message adds a Received header on top; the receiving server adds an Authentication-Results header with what it verified. The tool answers: 1. **Which route did the message take, and where did it wait?** The Received hops, oldest first, with delays and TLS. 2. **Did the sender prove who they are?** SPF, DKIM and DMARC as the receiver recorded them. 3. **Do the identities line up?** From, Return-Path and the DKIM signing domain compared exactly; Reply-To checked against From. 4. **Who owns the sending addresses?** On request only, through public DNS and the network registry. It does not verify any signature; it reads what the receiver wrote. ## Inputs ### Raw headers Paste the header block of a message: Gmail, open the message, the three-dot menu, "Show original"; Outlook on the web, the three-dot menu, "View message source"; Apple Mail, View, Message, All Headers. Parsing starts as soon as the text changes. Everything after the first blank line is treated as the body and ignored; folded continuation lines are joined back onto their field. Text with no `Name: value` lines is refused with "No headers found". ### An .eml file Drop the file anywhere on the page, or use Open file, up to 5 MiB. Only the header block is read into the field; the body never reaches the page. ## Reading the result ### Verdict and chips The verdict leads with what the receiver reports: DMARC passed (through DKIM or SPF when one aligns) or failed for the From domain, raised to a CHECK when Reply-To points elsewhere; without a DMARC result it names the first failure, the Reply-To difference, clock skew, or simply that the route was traced. The detail gives the hop count, the end-to-end time and the longest wait. The chips show each recorded result, the hops with their time, and a Reply-To warning; each is a button that scrolls to the section that explains it. ### Findings Everything found, worst first; passes fold into one line. An INFO finding always reminds you that these are reported results. The [finding reference](#finding-reference) lists them all. ### Take it further Links that carry a value derived from the message into another tool: the DKIM key that signed it (selector and domain from the signature), SPF for the bounce domain, the DMARC policy of the From domain, the network behind the first public hop address, and the Date header as a Unix timestamp. Each opens the destination with the value already in its box; nothing is put in the URL. ### History History logs every Break it change with the headers it replaced; Revert undoes the newest, Reset input returns to what you entered. There are no Heal it repairs: headers are evidence, not something to fix. ### Route One row per hop, oldest first: the servers it went from and to, the address with its kind (sample, non-public), the protocol, a TLS badge, and the delay the previous server added, drawn as a bar. The longest wait over 30 seconds is marked. Under the route, Look up hop addresses sends the public addresses to the server and writes the network, registry country, AS number and reverse name next to each hop. ### Authentication The three results as the receiver recorded them, with the identity each one checked, and a table comparing the From domain with the Return-Path domain and every DKIM signing domain. ### Message and every header The identity fields with what each one means, and the complete header list with a filter. Values are shown as written: encoded words such as `=?UTF-8?B?...?=` in From or Subject are not decoded. ## Method Each rule below names the section of the specification it comes from. Where a rule is a Tamperbox choice and no specification asks for it, the source says "none". ### Reading the header block The text is cut at the first blank line, the boundary [RFC 5322 section 2.1](https://www.rfc-editor.org/rfc/rfc5322#section-2.1) defines between the header section and the body. A line that holds only spaces or tabs also counts as blank here. Lines starting with a space or tab are joined to the field above: "Unfolding is accomplished by simply removing any CRLF that is immediately followed by WSP" ([RFC 5322 section 2.2.3](https://www.rfc-editor.org/rfc/rfc5322#section-2.2.3)). The tool trims the continuation line and joins it with one space, so runs of white space inside a folded value become a single space. A field is `name: value`. The name must be printable US-ASCII except the colon, the rule of [RFC 5322 section 2.2](https://www.rfc-editor.org/rfc/rfc5322#section-2.2); a line that is neither a field nor a continuation is skipped without a message. With no fields at all, the input is refused. Field names are matched without regard to case. ### Route: hop order and clauses Received headers are reversed, so the first hop is the oldest. That order is reliable because "SMTP servers MUST prepend Received lines to messages; they MUST NOT change the order of existing lines" ([RFC 5321 section 4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4)). From each Received header the tool takes the `from`, `by` and `with` clauses and the timestamp after the last semicolon, following the Stamp grammar of [RFC 5321 section 4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4). The address is the first IPv4 address in the `from` clause and its TCP-info comment, else an IPv6 address literal there (`[IPv6:...]`, [RFC 5321 section 4.1.3](https://www.rfc-editor.org/rfc/rfc5321#section-4.1.3)), else any IPv4 address anywhere in the header. That last fallback can pick up the receiving server's own address. An address outside public ranges is labelled non-public. The timestamp is read with the browser's date parser after a trailing comment is removed. A hop's delay is its timestamp minus the previous hop's: how long the earlier server held the message. The end-to-end time runs from the oldest stamp to the newest. ### Route rules | Rule | Severity | Title | Source | | --- | --- | --- | --- | | The longest delay exceeds 30 seconds | CHECK | N s at server (the server that held the message) | none (Tamperbox threshold) | | A hop is stamped more than 2 seconds before the hop before it | INFO | Clock skew at hop N | [RFC 5321 §4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4) | | A hop has a `from` clause, no TLS marker, and a public address | CHECK | No TLS into server | [RFC 3848 §1](https://www.rfc-editor.org/rfc/rfc3848#section-1) | Clock skew relies on header order over timestamps: the order is a MUST, while dates only carry "SHOULD use explicit offsets in the dates (e.g., -0800), rather than time zone names" ([RFC 5321 section 4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4)). A hop counts as encrypted when its header mentions `ESMTPS`, `ESMTPSA`, `TLS` or `version=TLS` anywhere. [RFC 3848 section 1](https://www.rfc-editor.org/rfc/rfc3848#section-1) defines ESMTPS as "the use of ESMTP when STARTTLS [1] is also successfully negotiated". The other registered encrypted types, `LMTPS`, `LMTPSA` and the `UTF8SMTPS` family from [RFC 6531 section 4.3](https://www.rfc-editor.org/rfc/rfc6531#section-4.3), are not recognised unless the header also mentions TLS. ### Authentication results: which header The topmost `Authentication-Results` header is read, or the topmost `ARC-Authentication-Results` when there is none. Topmost is the newest, because the field "MUST be treated as though it were a trace header field" and "MUST be prepended to the message" ([RFC 8601 section 4.1](https://www.rfc-editor.org/rfc/rfc8601#section-4.1)). Lower Authentication-Results headers are ignored, including a second one from the same receiver. The value is split on semicolons, following `resinfo` in [RFC 8601 section 2.2](https://www.rfc-editor.org/rfc/rfc8601#section-2.2). The first part is shown as the reporting server, the authserv-id of [RFC 8601 section 2.5](https://www.rfc-editor.org/rfc/rfc8601#section-2.5). Every later part that starts with `method=result` becomes an entry, with its `ptype.property` values (`smtp.mailfrom`, `header.i`, `header.d`, `header.s`, `header.from`). When a method appears more than once, a passing entry is preferred. The authserv-id is shown, never checked against a list of servers you trust. Section 2.5 says consumers "SHOULD use this identifier to determine whether or not the data contained in an Authentication-Results header field ought to be used or ignored". The tool leaves that decision to you and says so in the INFO finding. ### Authentication rules | Rule | Severity | Title | Source | | --- | --- | --- | --- | | Always | INFO | Reported results, not independent verification | [RFC 8601 §7.1](https://www.rfc-editor.org/rfc/rfc8601#section-7.1) | | No entries read from the header | INFO | No Authentication-Results header | [RFC 8601 §2.2](https://www.rfc-editor.org/rfc/rfc8601#section-2.2) | | DMARC pass | PASS | DMARC passed | [RFC 9989 §5.3.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.5) | | DMARC fail or permerror | FAIL | DMARC result | [RFC 9989 §5.3.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.5) | | SPF pass for a Return-Path domain that is not the From domain | INFO | SPF passed but is not aligned | [RFC 9989 §4.4.2](https://www.rfc-editor.org/rfc/rfc9989#section-4.4.2) | | SPF fail or permerror | FAIL | SPF result | [RFC 7208 §2.6](https://www.rfc-editor.org/rfc/rfc7208#section-2.6) | | DKIM none | INFO | DKIM none | [RFC 8601 §2.7.1](https://www.rfc-editor.org/rfc/rfc8601#section-2.7.1) | | DKIM fail or permerror | FAIL | DKIM result | [RFC 8601 §2.7.1](https://www.rfc-editor.org/rfc/rfc8601#section-2.7.1) | ### Authentication rules: the sentences behind them DMARC decides the verdict. [RFC 9989 section 5.3.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.5): "If one or more of the Authenticated Identifiers align with the Author Domain, the message is considered to pass the DMARC mechanism check." The tool takes the receiver's word for which side of that line the message fell. It treats `none` as informational, consistent with [RFC 9989 section 9.2](https://www.rfc-editor.org/rfc/rfc9989#section-9.2) registers as "No DMARC Policy Record exists for the Author Domain". SPF results follow [RFC 7208 section 2.6](https://www.rfc-editor.org/rfc/rfc7208#section-2.6). The tool treats `neutral` and `none` as informational, following [RFC 7208 section 8.2](https://www.rfc-editor.org/rfc/rfc7208#section-8.2), which says: "A "neutral" result MUST be treated exactly like the "none" result". `softfail` is a CHECK here; section 8.5 says receivers "SHOULD NOT reject the message based solely on this result". DKIM results follow [RFC 8601 section 2.7.1](https://www.rfc-editor.org/rfc/rfc8601#section-2.7.1): `none` means "The message was not signed", so it is INFO; fail and permerror are FAIL, temperror is CHECK, and neutral and other results are INFO. ### Alignment Alignment is an exact domain match, compared in lower case. [RFC 9989 section 3.2.10.2](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.10.2) calls this strict alignment: "When the Author Domain (Section 3.2.2) is identical to an Authenticated Identifier (Section 3.2.1), the two are said to be in strict alignment." Relaxed alignment ([section 3.2.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.10.1)) needs the Organizational Domain, which RFC 9989 finds with a DNS tree walk ([section 4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10)). The tool makes no DNS queries for authentication, so relaxed alignment is not evaluated. The Return-Path domain is compared with the From domain, and every `d=` of a DKIM-Signature header ([RFC 6376 section 3.5](https://www.rfc-editor.org/rfc/rfc6376#section-3.5)) is compared with From. A DMARC pass is attributed to DKIM or SPF only when one of them matches exactly; a DKIM domain that is a parent or subdomain of From is labelled as a domain relationship. The From domain is extracted from a single mailbox after excluding display names and nested comments. The value `"ceo@bank.example" <x@evil.example>` yields `evil.example`. Ambiguous lists, multiple From fields and unsupported syntax yield an unknown domain; encoded display words are not decoded. See [RFC 5322 section 3.4](https://www.rfc-editor.org/rfc/rfc5322#section-3.4). ### Reply identity A Reply-To domain that is neither the From domain nor one of its subdomains is CHECK, "Replies go to X". Source: none; this is a Tamperbox phishing heuristic. [RFC 5322 section 3.6.2](https://www.rfc-editor.org/rfc/rfc5322#section-3.6.2) only says Reply-To "indicates the address(es) to which the author of the message suggests that replies be sent". With a DMARC pass, the verdict keeps the pass and is raised to a CHECK. ### Hop address lookup Nothing leaves the browser until you choose Look up hop addresses. Then up to 50 unique public addresses are sent to the server, three at a time, which returns the autonomous system, organisation and registry country from the network registry and the reverse name from public DNS. Documentation ranges are answered on the page without a request. Partial answers are counted and can be retried. Source: none; this is a Tamperbox convenience, not part of any mail standard. ## Standards and conformance The analyzer is a reader of trace and authentication headers. Everything in this section runs in your browser on the text you pasted. The only network request the code can make is the optional hop address lookup, which sends public IP addresses and nothing from the authentication section. The tool does not re-verify DKIM signatures, re-evaluate SPF, look up DMARC records or validate ARC seals. It reports what the receiver recorded, and where it parses more loosely than a specification allows, the tables below say so. ### RFC 5322 Internet Message Format [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322), Draft Standard, updated by [RFC 6854](https://www.rfc-editor.org/rfc/rfc6854). | Section | Requirement | What the tool does | | --- | --- | --- | | [2.1](https://www.rfc-editor.org/rfc/rfc5322#section-2.1) | An empty line separates the header section from the body | Cuts at the first empty line; a line of only white space also ends the header | | [2.2](https://www.rfc-editor.org/rfc/rfc5322#section-2.2) | Field name of printable US-ASCII except colon | Same character range; lines that do not match are skipped silently | | [2.2.3](https://www.rfc-editor.org/rfc/rfc5322#section-2.2.3) | Unfold by removing CRLF before WSP | Unfolds, but trims and joins with one space | | [3.3](https://www.rfc-editor.org/rfc/rfc5322#section-3.3) | date-time syntax | Read by the browser's date parser, which also accepts obsolete forms | | [3.4](https://www.rfc-editor.org/rfc/rfc5322#section-3.4) | `name-addr = [display-name] angle-addr` | Single mailbox parsed with display names and comments excluded; ambiguous input stays unknown | | [3.6.2](https://www.rfc-editor.org/rfc/rfc5322#section-3.6.2) | From is a mailbox list; Reply-To an address list | Only the first address of each is used | | [3.6.7](https://www.rfc-editor.org/rfc/rfc5322#section-3.6.7) | Return-Path and Received are trace fields | Read as trace; only the first Return-Path is used | The display-name gap matters for phishing. A From of `"ceo@bank.example" <x@evil.example>` is reported as from `bank.example`. Read the From row in Message and every header before you trust the domain. ### RFC 5321 SMTP trace information [RFC 5321](https://www.rfc-editor.org/rfc/rfc5321), Draft Standard, updated by [RFC 7504](https://www.rfc-editor.org/rfc/rfc7504). | Section | Requirement | What the tool does | | --- | --- | --- | | [4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4) | Received lines are prepended and never reordered | Reverses them to get the route oldest first | | [4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4) | Stamp: `FROM`, `BY`, optional `WITH`, then `;` and date-time | Takes the first `from`, `by` and `with` words and the text after the last `;` | | [4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4) | The FROM clause SHOULD carry the address from the TCP connection | Takes the first address in the clause, with fallbacks described under Method | | [4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4) | obs- date forms MUST NOT be used in SMTP | Accepts them; a stamp in `EST` is read without a warning | | [4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4) | Return-Path preserves the MAIL FROM reverse-path | Uses the Return-Path domain as the SPF identity for alignment | | [4.1.3](https://www.rfc-editor.org/rfc/rfc5321#section-4.1.3) | IPv6 address literal `[IPv6:...]` | Recognised in the `from` clause | Received headers below your own receiver were written by servers you do not control. Section 4.4 says a mail program "MUST NOT change or delete a Received: line", but nothing stops a sender from adding false ones before the first real hop. The tool draws them like any other hop. ### RFC 3848 and RFC 6531 transmission types [RFC 3848](https://www.rfc-editor.org/rfc/rfc3848), Draft Standard, registers `ESMTPA`, `ESMTPS`, `ESMTPSA`, `LMTP`, `LMTPA`, `LMTPS` and `LMTPSA` for the `with` clause ([section 1](https://www.rfc-editor.org/rfc/rfc3848#section-1)). [RFC 6531](https://www.rfc-editor.org/rfc/rfc6531), Proposed Standard, adds the `UTF8SMTP` family, including `UTF8SMTPS` "ESMTP with SMTPUTF8 and STARTTLS" ([section 4.3](https://www.rfc-editor.org/rfc/rfc6531#section-4.3)). | Type | Means encrypted | Tool counts it as TLS | | --- | --- | --- | | `ESMTPS`, `ESMTPSA` | Yes | Yes | | `LMTPS`, `LMTPSA` | Yes | Only if `TLS` appears elsewhere in the header | | `UTF8SMTPS`, `UTF8SMTPSA` | Yes | Only if `TLS` appears elsewhere in the header | | Any type, with `TLS` in a comment | Not defined by these RFCs | Yes | The No TLS finding only applies to hops with a public address, so the usual LMTP hop to a mailbox store on an internal address is not flagged. [RFC 3848 section 3](https://www.rfc-editor.org/rfc/rfc3848#section-3) warns that these keywords "should not be used for mail filtering or relaying decisions except in very controlled environments"; the tool uses them only for a CHECK. ### RFC 8601 Authentication-Results: parsing [RFC 8601](https://www.rfc-editor.org/rfc/rfc8601), Proposed Standard. | Section | Requirement | What the tool does | | --- | --- | --- | | [2.2](https://www.rfc-editor.org/rfc/rfc8601#section-2.2) | `authserv-id [version] (no-result / 1*resinfo)` | Splits on every `;` and shows the first part, version included, as the server | | [2.2](https://www.rfc-editor.org/rfc/rfc8601#section-2.2) | `no-result` is the literal `none` | Not recognised: the header is reported as missing | | [2.2](https://www.rfc-editor.org/rfc/rfc8601#section-2.2) | Comments (CFWS) may appear between tokens | A `;` inside a comment or quoted `reason` cuts the entry short and its properties are lost | | [2.3](https://www.rfc-editor.org/rfc/rfc8601#section-2.3) | `ptype.property=pvalue` | Read for every dotted property; `reason` is not read | | [2.6](https://www.rfc-editor.org/rfc/rfc8601#section-2.6) | A method may carry a version, `dkim/1` | Not recognised: the entry is dropped | | [2.7.1](https://www.rfc-editor.org/rfc/rfc8601#section-2.7.1), [2.7.2](https://www.rfc-editor.org/rfc/rfc8601#section-2.7.2) | DKIM and SPF result sets | Pass, none and failure, as listed under Method | | [4.1](https://www.rfc-editor.org/rfc/rfc8601#section-4.1) | Ignore unregistered results and unsupported methods | Shows only `spf`, `dkim` and `dmarc`; other methods are read but not displayed | The `;` problem is not theoretical: the expanded example in [RFC 7208 section 9.2](https://www.rfc-editor.org/rfc/rfc7208#section-9.2) has `reason="client-ip=192.0.2.1; smtp.helo=foo.example.com"`, which the tool splits in two. ### RFC 8601 Authentication-Results: trust | Section | Requirement | What the tool does | | --- | --- | --- | | [2.5](https://www.rfc-editor.org/rfc/rfc8601#section-2.5) | Consumers SHOULD use the authserv-id to decide whether to use the header | Shows it; you decide | | [4.1](https://www.rfc-editor.org/rfc/rfc8601#section-4.1) | MUAs and filters "SHOULD NOT interpret this header field unless specifically configured to do so" | You start the reading by pasting; there is no trusted-server list | | [5](https://www.rfc-editor.org/rfc/rfc8601#section-5) | The receiving MTA MUST delete forged copies claiming its own authserv-id | Out of scope: the tool is not an MTA and assumes your receiver did this | | [7.1](https://www.rfc-editor.org/rfc/rfc8601#section-7.1) | Forged header fields: a trusted list "should initially be empty" | Always adds the INFO finding that results are reported, not verified | RFC 8601 says processing should not be on by default; the tool reads the header because that is its whole job, and every result is labelled as the receiver's claim. If the topmost header was added by a server outside your own mail system, or by the sender, treat every result on the page as unverified. ### RFC 7208 SPF [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208), Proposed Standard, updated by [RFC 7372](https://www.rfc-editor.org/rfc/rfc7372), [RFC 8553](https://www.rfc-editor.org/rfc/rfc8553) and [RFC 8616](https://www.rfc-editor.org/rfc/rfc8616). | Section | Requirement | What the tool does | | --- | --- | --- | | [2.4](https://www.rfc-editor.org/rfc/rfc7208#section-2.4) | With a null reverse-path, MAIL FROM is `postmaster@` the HELO identity | Not applied: a Return-Path of `<>` has no domain, so the Return-Path row shows none | | [2.6](https://www.rfc-editor.org/rfc/rfc7208#section-2.6) | Seven results: none, neutral, pass, fail, softfail, temperror, permerror | Displays the recorded result as written | | [4](https://www.rfc-editor.org/rfc/rfc7208#section-4) | check_host() evaluation | Not performed; no DNS query is made | | [8.2](https://www.rfc-editor.org/rfc/rfc7208#section-8.2) | Neutral MUST be treated exactly like none | Both are informational | | [8.5](https://www.rfc-editor.org/rfc/rfc7208#section-8.5) | Softfail is between fail and none | Reported as CHECK | | [9.2](https://www.rfc-editor.org/rfc/rfc7208#section-9.2) | SPF results in Authentication-Results with `smtp.mailfrom` | Shows `smtp.mailfrom` as the checked identity; alignment uses Return-Path instead | The `smtp.mailfrom` the receiver recorded and the Return-Path domain usually agree. When they do not, the SPF tile and the alignment table show different domains. ### RFC 6376 DKIM [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376), Internet Standard, updated by [RFC 8301](https://www.rfc-editor.org/rfc/rfc8301), [RFC 8463](https://www.rfc-editor.org/rfc/rfc8463), [RFC 8553](https://www.rfc-editor.org/rfc/rfc8553) and [RFC 8616](https://www.rfc-editor.org/rfc/rfc8616). | Section | Requirement | What the tool does | | --- | --- | --- | | [3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2) | DKIM-Signature is a tag=value list | Parsed for `d=`, `s=` and `a=` | | [3.5](https://www.rfc-editor.org/rfc/rfc6376#section-3.5) | `d=` is the signing domain (SDID) | Compared with the From domain for alignment | | [6](https://www.rfc-editor.org/rfc/rfc6376#section-6) | "Verifiers MUST produce a result that is semantically equivalent to applying the steps listed in Sections 6.1, 6.1.1, and 6.1.2" | Not a verifier: no key lookup, no body hash, no signature check | Because it does not verify, the tool compares every `d=` it finds, including signatures the receiver marked as failed. With one aligned signature that failed and an unaligned one that passed, it still says DMARC passed through DKIM. RFC 9989 counts only a validated `d=` ([section 3.2.3](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.3)). The receiver's own DMARC result is still the one shown. ### RFC 9989 DMARC [RFC 9989](https://www.rfc-editor.org/rfc/rfc9989), Proposed Standard, May 2026. It obsoletes RFC 7489 together with [RFC 9990](https://www.rfc-editor.org/rfc/rfc9990) (aggregate reporting) and [RFC 9991](https://www.rfc-editor.org/rfc/rfc9991) (failure reporting); the tool uses neither report format. | Section | Requirement | What the tool does | | --- | --- | --- | | [3.2.4](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.4) | The SPF Domain is the SPF-validated MAIL FROM | Uses the Return-Path domain | | [3.2.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.10.1) | Relaxed alignment: same Organizational Domain | Not evaluated | | [3.2.10.2](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.10.2) | Strict alignment: identical domains | Evaluated, without checking that SPF or DKIM passed | | [4.4](https://www.rfc-editor.org/rfc/rfc9989#section-4.4) | Domain comparisons are case-insensitive | Lower-cases before comparing | | [4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10) | DNS tree walk for policy and Organizational Domain | Not performed | | [5.3.1](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.1) | Zero or several From domains: validation is not possible | Uses the first domain and carries on | | [5.3.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.5) | Pass when an Authenticated Identifier aligns | Takes the receiver's recorded result | | [9.2](https://www.rfc-editor.org/rfc/rfc9989#section-9.2) | Result names pass, fail, none, temperror, permerror | Pass is PASS; none is INFO; temperror is CHECK; fail and permerror are FAIL | The `dmarc=none` result is informational: it indicates no applicable policy, rather than a failed authentication check. ### RFC 8617 ARC [RFC 8617](https://www.rfc-editor.org/rfc/rfc8617), Experimental. Not on the standards track. | Section | Requirement | What the tool does | | --- | --- | --- | | [4.1.1](https://www.rfc-editor.org/rfc/rfc8617#section-4.1.1) | AAR is `instance ";" authres-payload` | Read only when no Authentication-Results header exists; the instance tag `i=1` is shown as the server name and the real authserv-id is skipped | | [4.2.1](https://www.rfc-editor.org/rfc/rfc8617#section-4.2.1) | Instance tags order ARC sets | Not used; the topmost AAR is taken | | [5.2](https://www.rfc-editor.org/rfc/rfc8617#section-5.2) | Validator actions on ARC-Seal and ARC-Message-Signature | Not performed | An ARC-Authentication-Results header records what an intermediary saw, and without seal validation anyone could have written it. ### RFC 2047 encoded words [RFC 2047](https://www.rfc-editor.org/rfc/rfc2047), Draft Standard. Encoded words ([section 2](https://www.rfc-editor.org/rfc/rfc2047#section-2)) are not decoded; From, Subject and other values are shown as written. The From domain is unaffected, because encoded words may not appear in an addr-spec ([section 5](https://www.rfc-editor.org/rfc/rfc2047#section-5)). ## Finding reference The RFC section column links the rule each finding comes from. "none" marks a Tamperbox recommendation that no specification requires. ### Authentication findings | Finding | Severity | What it means | What to do | RFC section | | --- | --- | --- | --- | --- | | Reported results, not independent verification | INFO | The receiver's word, not a re-check | Confirm the reporting server is yours | [RFC 8601 §7.1](https://www.rfc-editor.org/rfc/rfc8601#section-7.1) | | No Authentication-Results header | INFO | Nothing was recorded, the header says `none`, or the headers came from the sender's side | Copy from the received message | [RFC 8601 §2.2](https://www.rfc-editor.org/rfc/rfc8601#section-2.2) | | DMARC passed | PASS | The receiver found an aligned SPF or DKIM pass | | [RFC 9989 §5.3.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.5) | | DMARC fail (or other) | FAIL | The From domain was not proven; `none` means it has no DMARC policy | Treat as unverified; if yours, fix SPF or DKIM alignment | [RFC 9989 §9.2](https://www.rfc-editor.org/rfc/rfc9989#section-9.2) | | SPF passed but is not aligned | INFO | Normal for a mail service; DMARC relies on DKIM | Nothing | [RFC 9989 §4.4.2](https://www.rfc-editor.org/rfc/rfc9989#section-4.4.2) | | SPF fail, permerror | FAIL | The receiver reports failure or a permanent evaluation error | Add the server to the record, if the message is yours | [RFC 7208 §2.6](https://www.rfc-editor.org/rfc/rfc7208#section-2.6) | | DKIM none | INFO | The message was not signed | Sign outgoing mail | [RFC 8601 §2.7.1](https://www.rfc-editor.org/rfc/rfc8601#section-2.7.1) | | DKIM fail (or other) | FAIL | The signature did not verify or could not be checked | Check the key; look for a forwarder that altered the message | [RFC 8601 §2.7.1](https://www.rfc-editor.org/rfc/rfc8601#section-2.7.1) | ### Identity and route findings | Finding | Severity | What it means | What to do | RFC section | | --- | --- | --- | --- | --- | | Replies go to X | CHECK | Answers leave the From domain | Verify the sender before replying | none (Tamperbox heuristic) | | N s at server | CHECK | The longest wait on the route | Nothing, unless it repeats | none (Tamperbox threshold) | | Clock skew at hop N | INFO | Server clocks disagree; header order still holds | Fix the clock if the server is yours | [RFC 5321 §4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4) | | No TLS into server | CHECK | The hop was not recorded as encrypted | Enable STARTTLS; publish MTA-STS | [RFC 3848 §1](https://www.rfc-editor.org/rfc/rfc3848#section-1) | ## Guide ### Is this message genuine? 1. Confirm that the server named in Authentication-Results is your own receiving server; everything below it was written by the sender. 2. Read the DMARC result. A pass means the From domain was proven; a fail means it was not. 3. Check Reply-To and Return-Path. A reply address on another domain is the common shape of phishing that asks you to answer. 4. Read the From header itself in Message and every header. The display name may claim a different address than the actual mailbox; compare them. 5. If in doubt, contact the supposed sender through a channel you already have. ### My own mail fails DMARC 1. Open the DKIM key that signed it (Take it further) and confirm it is published and strong enough. 2. Open SPF for the bounce domain and confirm the sending service is listed. 3. Make the service sign with your domain, not its own, so DKIM aligns even when the bounce domain does not. ### A long delay A wait over 30 seconds at one server is usually a queue, a content filter or a greylisting retry. If it repeats, ask the operator of that server. The route names the server that held the message. ### Clock skew A hop stamped before the one under it means a server's clock is wrong. The order of the headers is what counts. Fix the clock with NTP if the server is yours. ### Break it cases Each case is built from the headers you pasted, keeping every other line. | Case | What it does to the headers | | --- | --- | | Reply-To elsewhere | Sets Reply-To to a look-alike domain | | All checks fail | Replaces Authentication-Results with spf=fail, dkim=none, dmarc=fail and a look-alike Return-Path | | Clock skew | Restamps the newest Received header 70 seconds before the one under it | | Not headers | Loads a sentence that is not a header block | ## Worked example The page opens on an order confirmation sent through a mail service, built from documentation addresses and the reserved `.example` zone. Four hops: the sender's laptop to `out.harbor-supply.example`, to the mail service `mail-sor-f17.inboxcloud.example`, to `mx.receiver.example`, to the mailbox store, 41 seconds end to end, 38 of them at the mail service. **Receiver reports: DMARC passed through DKIM.** SPF passed for `send.bulkpost.example`, the mail service's bounce domain, so the only aligned identity is the DKIM signature `d=harbor-supply.example; s=google`. The findings are the 38-second wait (CHECK), two INFO notes, and the DMARC pass. Look up hop addresses answers from local sample data, so nothing is sent. Replace the sample with your own headers and every section, card and link is rewritten for them. ## For agents The Tamperbox MCP server runs the same analysis. Search its catalog for the header operation, inspect the input schema, and call it with the header block. Keep the warning block with any conclusion: - Results are what the receiving server recorded; nothing is re-verified. - Headers below the trusted receiver can be forged. - Alignment is an exact domain match; delays depend on each server's clock. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for what travels when addresses are looked up. ## Limits - No signature or ARC verification; no DNS lookup for the authentication section. - Exact alignment only. - The topmost Authentication-Results header only. - From supports a single mailbox with display names and comments; ambiguous lists remain unknown and encoded words are not decoded. - Hop lookups: up to 50 public addresses, only on request; country is registry data, not location. - Nothing is stored. ## References | Specification | Status | Sections used | | --- | --- | --- | | [RFC 5322, Internet Message Format](https://www.rfc-editor.org/rfc/rfc5322) | Draft Standard, updated by RFC 6854 | [2.1](https://www.rfc-editor.org/rfc/rfc5322#section-2.1), [2.2](https://www.rfc-editor.org/rfc/rfc5322#section-2.2), [2.2.3](https://www.rfc-editor.org/rfc/rfc5322#section-2.2.3), [3.3](https://www.rfc-editor.org/rfc/rfc5322#section-3.3), [3.4](https://www.rfc-editor.org/rfc/rfc5322#section-3.4), [3.6.2](https://www.rfc-editor.org/rfc/rfc5322#section-3.6.2), [3.6.7](https://www.rfc-editor.org/rfc/rfc5322#section-3.6.7) | | [RFC 5321, Simple Mail Transfer Protocol](https://www.rfc-editor.org/rfc/rfc5321) | Draft Standard, updated by RFC 7504 | [4.1.3](https://www.rfc-editor.org/rfc/rfc5321#section-4.1.3), [4.4](https://www.rfc-editor.org/rfc/rfc5321#section-4.4) | | [RFC 3848, ESMTP and LMTP Transmission Types Registration](https://www.rfc-editor.org/rfc/rfc3848) | Draft Standard | [1](https://www.rfc-editor.org/rfc/rfc3848#section-1), [3](https://www.rfc-editor.org/rfc/rfc3848#section-3) | | [RFC 6531, SMTP Extension for Internationalized Email](https://www.rfc-editor.org/rfc/rfc6531) | Proposed Standard | [4.3](https://www.rfc-editor.org/rfc/rfc6531#section-4.3) | | [RFC 8601, Message Header Field for Indicating Message Authentication Status](https://www.rfc-editor.org/rfc/rfc8601) | Proposed Standard | [2.2](https://www.rfc-editor.org/rfc/rfc8601#section-2.2), [2.3](https://www.rfc-editor.org/rfc/rfc8601#section-2.3), [2.5](https://www.rfc-editor.org/rfc/rfc8601#section-2.5), [2.6](https://www.rfc-editor.org/rfc/rfc8601#section-2.6), [2.7.1](https://www.rfc-editor.org/rfc/rfc8601#section-2.7.1), [2.7.2](https://www.rfc-editor.org/rfc/rfc8601#section-2.7.2), [4.1](https://www.rfc-editor.org/rfc/rfc8601#section-4.1), [5](https://www.rfc-editor.org/rfc/rfc8601#section-5), [7.1](https://www.rfc-editor.org/rfc/rfc8601#section-7.1) | | [RFC 7208, Sender Policy Framework](https://www.rfc-editor.org/rfc/rfc7208) | Proposed Standard, updated by RFC 7372, 8553, 8616 | [2.4](https://www.rfc-editor.org/rfc/rfc7208#section-2.4), [2.6](https://www.rfc-editor.org/rfc/rfc7208#section-2.6), [4](https://www.rfc-editor.org/rfc/rfc7208#section-4), [8.2](https://www.rfc-editor.org/rfc/rfc7208#section-8.2), [8.5](https://www.rfc-editor.org/rfc/rfc7208#section-8.5), [9.2](https://www.rfc-editor.org/rfc/rfc7208#section-9.2) | | [RFC 6376, DomainKeys Identified Mail Signatures](https://www.rfc-editor.org/rfc/rfc6376) | Internet Standard, updated by RFC 8301, 8463, 8553, 8616 | [3.2](https://www.rfc-editor.org/rfc/rfc6376#section-3.2), [3.5](https://www.rfc-editor.org/rfc/rfc6376#section-3.5), [6](https://www.rfc-editor.org/rfc/rfc6376#section-6) | | [RFC 9989, DMARC](https://www.rfc-editor.org/rfc/rfc9989) | Proposed Standard; obsoletes RFC 7489 with RFC 9990 and 9991 | [3.2.3](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.3), [3.2.4](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.4), [3.2.10.1](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.10.1), [3.2.10.2](https://www.rfc-editor.org/rfc/rfc9989#section-3.2.10.2), [4.4](https://www.rfc-editor.org/rfc/rfc9989#section-4.4), [4.4.2](https://www.rfc-editor.org/rfc/rfc9989#section-4.4.2), [4.10](https://www.rfc-editor.org/rfc/rfc9989#section-4.10), [5.3.1](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.1), [5.3.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.5), [9.2](https://www.rfc-editor.org/rfc/rfc9989#section-9.2) | | [RFC 9990, DMARC Aggregate Reporting](https://www.rfc-editor.org/rfc/rfc9990) | Proposed Standard | none; cited as a successor of RFC 7489 | | [RFC 9991, DMARC Failure Reporting](https://www.rfc-editor.org/rfc/rfc9991) | Proposed Standard | none; cited as a successor of RFC 7489 | | [RFC 8617, Authenticated Received Chain](https://www.rfc-editor.org/rfc/rfc8617) | Experimental | [4.1.1](https://www.rfc-editor.org/rfc/rfc8617#section-4.1.1), [4.2.1](https://www.rfc-editor.org/rfc/rfc8617#section-4.2.1), [5.2](https://www.rfc-editor.org/rfc/rfc8617#section-5.2) | | [RFC 2047, MIME Part Three: Message Header Extensions](https://www.rfc-editor.org/rfc/rfc2047) | Draft Standard, updated by RFC 2184, 2231 | [2](https://www.rfc-editor.org/rfc/rfc2047#section-2), [5](https://www.rfc-editor.org/rfc/rfc2047#section-5) | RFC 9990 and RFC 9991 are cited only as the documents that, with RFC 9989, replace RFC 7489; the tool reads no DMARC reports. For the key behind a message's signature, see the [DKIM Record Checker](https://docs.tamperbox.dev/tools/dkim-checker/). --- # Email Provider Lookup How Tamperbox attributes public MX hostnames to mailbox services and gateways, handles mixed routes, and preserves uncertainty about the downstream mailbox host. Canonical: https://docs.tamperbox.dev/tools/email-provider/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain whose inbound mail route you want to attribute Outputs: A provider verdict, route-by-route hostname evidence, public MX records and limitations Limitations: Attribution is inferred from published MX hostnames and cannot prove mailbox ownership or reveal a host concealed behind a gateway The tool page is [tamperbox.dev/email-provider](https://tamperbox.dev/email-provider). It opens on a live lookup of `tamperbox.dev`; replace that domain to investigate another inbound route. This guide documents exactly how the catalog matches hostnames, how routes are grouped and why some answers must remain unknown. <div class="tb-callout"><strong>Where processing happens:</strong> pasted text is cleaned and validated in the browser. The domain is sent to the Tamperbox server, which asks a public resolver for MX records. Provider grouping runs on the server response. Nothing is stored, no email is sent and no SMTP connection is opened.</div> ## What the tool answers The lookup answers which recognised service appears first in a domain's public inbound mail route. It distinguishes mailbox services from gateways because those statements have different evidence. A Microsoft 365 hostname can support “likely mailbox service”; a Mimecast hostname supports only “gateway detected, downstream mailbox unknown.” It also answers whether the route is mixed, partly recognised, entirely unknown, missing, explicitly disabled by null MX or inconclusive because DNS evidence cannot be interpreted. Each provider row names the exact hostname and preference behind the attribution. The tool does not infer from SPF, website hosting, nameservers, branding or a mail vendor's customer list. Those signals can belong to outgoing mail or unrelated infrastructure and would turn a bounded MX observation into a guess. ## Inputs ### Domain names Enter a public domain such as `example.com`. Browser validation lowercases capitals, removes one final dot, normalises full-width dots and converts international labels to their ASCII form. The parser refuses IP addresses, ports, paths, underscores, missing top-level domains, empty or oversized labels and labels with invalid hyphen placement. A maximum of 1,024 source characters is accepted. The canonical DNS name may be at most 253 characters, with labels of 63 characters or fewer. The server repeats the same validation before it makes a request. ### Pasted text and files Pasting `https://example.com/about`, `person@example.com`, `mailto:person@example.com`, or a quoted variant keeps only `example.com`, and the page announces the transformation. Text that yields no valid domain remains unchanged so the specific parser refusal is visible. Ordinary typing is never silently rewritten. The drop zone accepts a text file, a page-wide file drop and paste outside another field. File bytes are read in the browser and are not uploaded; only a valid domain derived from the text can be sent for DNS lookup. ### Reserved synthetic input Entering `harbor-supply.example` uses a fixed local mail-routing fixture instead of sending DNS requests. It contains one synthetic MX route and an unknown provider. This exception is for the documented reserved example only; other domains use the live server path. The checked line labels the synthetic run, and its records cannot demonstrate real delivery or provider ownership. ### Lookup timing and cancellation The request runs 700 milliseconds after typing stops, immediately on Enter, on field change, after a shared handoff, or through Refresh lookup. Clearing or editing cancels the active request and invalidates its generation. A late response cannot restore stale routes, cards or Copy result. ## Reading the result ### Verdict and findings The verdict answers the provider question: likely mailbox service, gateway, mixed route, unknown route, no provider or inconclusive. Chips show mail-routing state and each recognised service. Findings explain the route classification and the provider inference separately, worst first, so valid MX publication cannot hide an uncertain attribution. The privacy pair states what is local and what leaves the page. Copy result is available only for a completed result. Empty, invalid, loading and failed states hide stale evidence and copying. ### Inbound routes and DNS evidence Inbound routes are sorted by MX preference and hostname. Each row has provider, role, matched hostname and priority; the lowest preference is marked preferred. An unknown row stays “Not recognized,” not “self-hosted.” DNS evidence shows the underlying MX set and TTL. It remains the source of truth if a catalog label is questioned. History follows all evidence and supports Revert and Reset input; Take it further follows History and stays hidden because no honest same-category derived-value receiver exists today. ## Method ### Obtain usable MX evidence The shared routing engine follows [RFC 5321 section 5](https://www.rfc-editor.org/rfc/rfc5321#section-5): MX is queried first, CNAME traversal is bounded to eight hops, and every answer must have a preference from 0 to 65,535 plus a valid target. The normative sequence says a sender “first performs a DNS lookup for an MX record.” NXDOMAIN, null MX, empty MX with address fallback, no route, resolver failure and invalid MX are classified before provider matching. The provider catalog never overrides routing. A Google-looking hostname in a report whose routing status is not `mx` cannot produce a provider identification. ### Match complete hostnames Each MX target is lowercased and its final dot removed. Rules are anchored regular expressions for complete names. `route1.mx.cloudflare.net` matches Cloudflare Email Routing; `route1.mx.cloudflare.net.attacker.example` does not. Evidence is deduplicated by hostname and preference. The current catalog recognises Cloudflare Email Routing, Gmail consumer inbound, Google Workspace, Microsoft 365, Zoho Mail, Proton Mail, Fastmail, Mimecast, Proofpoint and Barracuda. Catalog membership is a Tamperbox inference, not an RFC registry. ### Group services and roles Matches are grouped by provider id. Every group carries a display name, a role of mailbox or gateway, and its supporting routes. A route at the lowest numeric preference is marked preferred. Several routes for one provider remain one provider group because they are redundant endpoints of the same published service. Gateway rules take precedence in interpretation, not DNS ordering. A gateway is the public receiving edge; it may filter, reject, archive or forward mail, but the hostname does not reveal where the mailbox is ultimately stored. ### Decide the provider status Exactly one recognised mailbox provider with no unknown routes is `identified`, and the mailbox host is recorded with confidence `inferred`. Any recognised gateway without another group is `gateway`. More than one provider group, or any recognised group plus unknown MX routes, is `mixed`. No recognised group is `unknown`. Non-MX routing states map to `no_mx` except resolver failure and invalid MX, which map to `inconclusive`. This preserves the difference between “no provider can exist in this evidence” and “the check could not tell.” ## Standards and conformance ### RFC 5321 routing evidence | Section | Requirement | How the tool applies it | | --- | --- | --- | | [5](https://www.rfc-editor.org/rfc/rfc5321#section-5) | Locate SMTP destinations through MX | Reads MX before any provider inference | | [5.1](https://www.rfc-editor.org/rfc/rfc5321#section-5.1) | Lower preference values are preferred | Sorts and marks the preferred public routes | | [5.1](https://www.rfc-editor.org/rfc/rfc5321#section-5.1) | Equal-preference hosts are alternatives | Keeps every row; does not select one mailbox owner | RFC 5321 defines routing, not provider identity. The tool conforms to the route ordering but adds a clearly labelled catalog inference. It stops before resolving targets, connecting to SMTP, following delivery through gateways or establishing an account relationship. ### RFC 7505 negative evidence | Section | Requirement | How the tool applies it | | --- | --- | --- | | [3](https://www.rfc-editor.org/rfc/rfc7505#section-3) | A domain accepting no mail publishes a single `0 .` MX | Reports no provider because the domain explicitly refuses mail | | [3](https://www.rfc-editor.org/rfc/rfc7505#section-3) | Null MX must not be mixed with ordinary routing | Shared routing marks a mixed or nonzero form invalid and provider inference inconclusive | The provider catalog does not run on a null MX. This prevents the absence of service from being confused with an unknown service. ### Catalog conformance boundary Provider rules are implementation data maintained with the code and its tests. Anchored patterns prevent substring impersonation; tests cover supported names, deceptive suffixes, mixed routes, duplicates, case and final dots. No vendor document standardises all customer MX patterns, so the catalog describes observed public naming contracts and can lag a provider change. ## Finding reference ### Positive and qualified attribution | Finding | Severity | Evidence | Meaning | | --- | --- | --- | --- | | Likely email provider | Pass | One mailbox group, no unknown routes | Published MX consistently points at that service; ownership remains inferred | | Gateway detected | Check | One gateway group, no other routes | The named service receives mail first; downstream mailbox stays unknown | | Multiple or partly recognized routes | Check | Several groups, or recognised plus unknown | No single mailbox host can be determined | | Email provider unknown | Info | No hostname matches | Catalog has no answer; self-hosting is only one possibility | ### Missing and inconclusive attribution | Finding | Severity | Evidence | Meaning | | --- | --- | --- | --- | | No email provider: null MX | Fail | Exact `0 .` route | The domain explicitly accepts no mail | | No email provider: NXDOMAIN | Fail | Public DNS says the domain does not exist | There is no public inbound route | | No MX provider identified | Check | Only address fallback or no route | Address records do not identify a mailbox platform | | Provider unknown: lookup failed | Check | Resolver or alias failure | Retry; this is not evidence of absence | | Provider unknown: MX uninterpretable | Check | Invalid or contradictory MX | Repair the DNS set before attribution | ### Catalog signatures | Provider | Role | Accepted hostname shape | | --- | --- | --- | | Cloudflare Email Routing | Gateway | `route` plus digits under `mx.cloudflare.net` | | Google Gmail | Mailbox | Gmail inbound names under `gmail-smtp-in.l.google.com` | | Google Workspace | Mailbox | `aspmx` variants, `googlemail.com` variants or `smtp.google.com` | | Microsoft 365 | Mailbox | Tenant under `mail.protection.outlook.com` or `mx.microsoft` | | Zoho, Proton, Fastmail | Mailbox | Their bounded regional inbound patterns | | Mimecast, Proofpoint, Barracuda | Gateway | Anchored gateway-specific suffixes with at least one tenant label | ## Guide ### Reproduce the evidence Run `dig +short MX example.com` or `nslookup -type=mx example.com`. Compare the exact targets and preferences with the route table. A provider label should be explainable from those hostnames alone. If the commands show different answers, wait for the previous TTL and compare resolvers before editing DNS. For a suspected deceptive name, compare the complete suffix. `tenant.mail.protection.outlook.com` can match Microsoft 365; `tenant.mail.protection.outlook.com.example.net` cannot. ### Resolve a gateway result Obtain a message that was legitimately delivered to the domain and inspect its Received chain in the [Email Header Analyzer](https://tamperbox.dev/email-header-analyzer). Start at the trusted receiving side and trace later hops after the named gateway. Do not trust arbitrary forwarded headers or claim the next hostname is the contractual mailbox provider without administrative evidence. Gateway administration, mail-flow connectors and billing records are stronger evidence than SPF. SPF normally describes outbound senders and does not answer who stores inbound mail. ### Review mixed routes | Situation | Investigation | Safe action | | --- | --- | --- | | Old and new mailbox services coexist | Check migration plan, TTL and provider admin panels | Remove the retired set only after delivery is confirmed on the new service | | Gateway plus mailbox MX coexist | Confirm whether direct MX is intentional fallback or bypass | Preserve filtering order; avoid exposing a bypass accidentally | | Recognised routes plus one unknown backup | Identify the operator and test authorised failover | Leave the provider verdict mixed until the route is understood | | Equal-preference providers | Treat them as peers | Do not assume the first displayed name receives all mail | ### Use Break it and Heal it Pasting an email address or URL demonstrates cleanup; capitals and a final dot demonstrate canonicalisation. IP addresses, underscore owners and single labels demonstrate pre-request refusals. Heal it offers the domain inside a refused email address or URL. History records replacements, Revert walks backward and Reset input restores the value that started the sequence. ## Worked example The live default is `tamperbox.dev`. On 21 October 2026 its lookup filled three MX rows and matched Cloudflare Email Routing. The correct conclusion was gateway detected with downstream mailbox unknown. In the same comparison, `github.com` and `microsoft.com` each presented one Microsoft 365 route and a simpler likely-provider answer. The default was selected because it teaches the most important distinction in this tool: an inbound service is not always the mailbox host. The observed records are not frozen into the page. Every load uses the production path, so service names, priorities, TTLs and conclusions can change. ## For agents Agents can run the live `email_provider` operation through Tamperbox MCP or analyse pasted MX records through the bounded capability operation. Always return the exact supporting hostnames, roles and preferences. Say “likely” for mailbox attribution and “gateway” for an edge service; never erase the limitation by shortening either to “uses provider X.” Treat `mixed`, `unknown` and `inconclusive` as useful outcomes. Do not enrich them with unrelated web hosting, SPF or nameserver guesses unless the user explicitly asks for a broader investigation and the evidence is labelled separately. Never infer that an account exists. ## Limits The observation comes from one public recursive resolver at one time. Private and split-horizon records are invisible, cached answers can be stale, and DNSSEC validation is outside this page. The tool does not resolve MX targets, trace SMTP, inspect tenant configuration or follow gateway delivery. The catalog is finite. Custom vanity names, resellers and newly changed provider naming can remain unknown. A matched hostname can still be delegated through a partner or configured incorrectly. Results are not stored, but a live lookup necessarily sends the domain to the Tamperbox server and public resolver. ## References - [RFC 5321](https://www.rfc-editor.org/rfc/rfc5321), Simple Mail Transfer Protocol, especially [section 5](https://www.rfc-editor.org/rfc/rfc5321#section-5) and [section 5.1](https://www.rfc-editor.org/rfc/rfc5321#section-5.1). Current Internet Standard; it defines routing rather than provider ownership. - [RFC 7505](https://www.rfc-editor.org/rfc/rfc7505), A Null MX Resource Record for Domains That Accept No Mail, especially [section 3](https://www.rfc-editor.org/rfc/rfc7505#section-3). Current Proposed Standard. --- # Exact-Length String Generator How the Exact-Length String Generator builds strings of an exact size in characters, UTF-16 units or UTF-8 bytes, what the limit test set contains, how counterstrings work, and how to test a length limit with them. Canonical: https://docs.tamperbox.dev/tools/string-length-generator/ Updated: 2026-10-25 Applies to: tamperbox.dev, October 2026 Prerequisites: The length limit to test, and if you know it, what the system counts Outputs: The string with Copy and Download, its length in every count, or the limit test set with each value's size and reason Limitations: Strings up to 1,000,000 units and limit sets up to 500,000 in the browser; nothing is sent anywhere The tool page is [tamperbox.dev/string-length-generator](https://tamperbox.dev/string-length-generator). It opens on a string of exactly 255 ASCII characters. <div class="tb-callout"><strong>Where processing happens:</strong> strings are built in your browser, and downloads are made on your device. No server request is made.</div> ## What the tool answers What exactly should I paste to test a length limit, and is the limit counted in characters, UTF-16 units or bytes? ## The three counts | Count | Who counts this way | Emoji 😀 | |---|---|---| | Characters (code points) | Python `len()`, most database CHAR limits | 1 | | UTF-16 units | JavaScript, Java and C# length, HTML `maxlength` | 2 | | UTF-8 bytes | Byte limits on columns, file names, HTTP headers | 4 | To find out what a field counts, generate the limit in each unit with the emoji fill: the one the field accepts exactly is the one it uses. ## Method ### One string The string is built from whole characters of the chosen fill, never half a surrogate pair. When the next character would go past the length, a plain `a` (one unit in every count) closes the gap, so any length can be hit exactly in any unit. ### Limit test set For a limit N: the empty value, one character, N - 1, N, N + 1, N - 2 characters with a space on each side, N spaces (up to 100,000) and 2N. Every value is exactly the size its name says, in the unit you chose. N must be accepted unchanged; N + 1 must be refused, not silently cut. ### Counterstring A counterstring such as `*3*5*7*9*12*` writes each asterisk's position before it. Built from the end backwards, it is always exactly N characters. Paste it into a field, read the last number left, and you know how many characters the field kept. It is ASCII, so all counts agree. ## Break it presets - **Emoji at the limit:** 255 characters of emoji: 510 UTF-16 units and 1,020 bytes. - **Bytes, not characters:** 255 UTF-8 bytes of CJK, which is 85 characters. - **JavaScript length:** 10 UTF-16 units of emoji, which is 5 characters. - **Split accents:** letters with combining accents that look half as long as their code point count. - **Limit test set** and **Counterstring** for 255 and 1,000. ## Limits A string is limited to 1,000,000 units and a limit set to 500,000 in the browser. Only the first 20,000 UTF-16 units are displayed; Copy and Download take the whole string with no line break added. ## Finding reference | Result at the limit | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | Maximum accepted unchanged | pass | | The limit is where it is documented | None | | Maximum + 1 refused with a message | pass | | The limit is enforced | None | | Maximum + 1 silently cut | fail | | Data loss without notice | Refuse over-long values, or show the cut | | Maximum refused | fail | | Off-by-one in the check | Use "length > max", not "length >= max" | | Fewer emoji than characters accepted | check | [HTML maxlength](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-maxlength) | The limit counts UTF-16 units or bytes | Count the same unit on client, server and database | | Accepted in the form, error on save | fail | [RFC 3629](https://www.rfc-editor.org/rfc/rfc3629) | The database counts bytes, the form counts characters | Size the column in characters, or check bytes on input | | Counterstring cut at an unexpected number | check | | Something truncates before the documented limit | Find the layer whose limit matches the number | ## Guide ### Find what a field counts 1. Set the documented limit and generate one string with the emoji fill in each unit. 2. Submit each. The one accepted exactly at the limit names the unit the field counts. ### Test a limit end to end Make the limit set, submit every value, and check the stored value as well as the form message. Maximum must be stored unchanged; maximum + 1 must be refused. ### Find where a value is cut Generate a long counterstring, submit it, and read the last number that survived in the stored value, a log or an export. That number is how many characters the slowest layer kept. ## Use it from an agent The `string_generate` operation takes the length as its input text and `unit`, `fill` and `mode` (`one`, `set` or `counter`) options. Through the API, strings are limited to 1,000,000 units, limit sets to 100,000, and output to the API's response size limit. See the [MCP documentation](https://docs.tamperbox.dev/mcp/). ## References - [RFC 3629: UTF-8](https://www.rfc-editor.org/rfc/rfc3629) - [RFC 2781: UTF-16](https://www.rfc-editor.org/rfc/rfc2781) - [HTML Standard: the maxlength attribute](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-maxlength) - [Unicode Standard Annex #29: Unicode Text Segmentation](https://www.unicode.org/reports/tr29/) --- # Getting started Pick a Tamperbox surface, run a small example, and keep the result's warnings and limits intact. Canonical: https://docs.tamperbox.dev/getting-started/ Updated: 2026-10-19 Applies to: MCP 0.2.0 Prerequisites: Node.js 22 or later for local MCP use Outputs: A working browser tool result or MCP client connection Limitations: Live network evidence can change between requests and regions. ## Pick a surface | Need | Use | | --- | --- | | Explore a tool visually | [tamperbox.dev](https://tamperbox.dev), with the method behind each finding under [Tool pages](https://docs.tamperbox.dev/tools/) | | Call one documented endpoint | Tamperbox REST API | | Let an agent discover and combine operations | Tamperbox MCP | ## Run the MCP server locally The released package starts a stdio server and uses the production Tamperbox API by default. ```sh npx -y tamperbox-mcp@0.2.0 ``` Most clients need the command split into an executable and arguments. Start with `npx`, then pass `-y` and `tamperbox-mcp@0.2.0` as arguments. ## Try a safe first task Ask the connected client: > Show me the input and output schemas for `json_format`. Do not run it yet. The agent should use `search`, return a focused schema fragment, and report `apiCalls: 0`. Next, give it synthetic JSON and ask it to format the value. That second task should use `execute`. ## Verify the boundary `search` reads the bundled OpenAPI snapshot and makes no API request. `execute` can call allowlisted Tamperbox API routes. Inputs embedded in executed code are visible to the MCP host, the API for each request, and the model provider carrying the tool call. Continue with [Connect a client](https://docs.tamperbox.dev/mcp/connect/) or [Code mode](https://docs.tamperbox.dev/mcp/code-mode/). --- # HAR File Sanitizer How the HAR File Sanitizer replaces credentials, cookies, keys and personal values in a HAR file with stable placeholders in the browser, what it detects and what it does not, and how to prepare a HAR file for a support ticket. Canonical: https://docs.tamperbox.dev/tools/har-sanitizer/ Updated: 2026-10-25 Applies to: tamperbox.dev, October 2026 Prerequisites: A HAR file exported from a browser's developer tools (Network panel, Save all as HAR or Export HAR), up to 50 MiB Outputs: A verdict, every replacement by request and place, the sanitized HAR to copy or download, and the request list with failures as a Markdown table Limitations: Detection is by field name and known patterns; names, postal addresses and phone numbers in free text are not detected; binary bodies are not inspected; nothing is sent anywhere The tool page is [tamperbox.dev/har-sanitizer](https://tamperbox.dev/har-sanitizer). It opens on a sample capture from a shop on the reserved `.example` domain: a sign-in that returns a token, an order list called with that token and a session cookie, and a checkout that fails with a card number in its body. <div class="tb-callout"><strong>Where processing happens:</strong> the HAR file is read and cleaned in your browser and never uploaded, including files you open or drop. No server request is made.</div> ## What the tool answers Can I attach this HAR file to a ticket? A HAR file records every request and response the browser made, with headers, cookies and bodies. Session cookies and bearer tokens in it let anyone holding the file act as the user until they expire. The tool replaces what it can find, tells you exactly what and where, and lists the requests so you can point support at the ones that failed. ## Inputs ### Pasted text Paste the HAR JSON into the box. Text over one million characters is kept out of the box so the page stays responsive; the box says what is loaded. ### Files Drop a `.har` or `.json` file anywhere on the page, or use Open file. Files up to 50 MiB are read in the browser. ### Options - **Every cookie value:** on by default. Cookie names stay, so you can see which cookies were sent. - **Email addresses** and **Card numbers:** on by default. - **IP addresses:** off by default, because they are usually needed to diagnose network problems. - **JSON Web Tokens:** keep claims and remove the signature (default), or replace the whole token. - **More field names to replace:** names your application uses for private values, such as `tenant` or `account_id`. ## Reading the result ### Verdict and chips How many distinct values were replaced, in how many requests, with a chip per kind, a chip for failed requests and a chip for binary bodies that were not inspected. ### What was replaced One row per place: the request number, the placeholder and where it was (`request header authorization`, `response body > access_token`, `request query`). Original values are never shown. ### Sanitized HAR The cleaned file, with Copy and Download. The download is named after your file with `.sanitized.har`. ### Requests Every request with method, status, sanitized URL and time. Failed means status 0 (blocked, cancelled or a network error) or 400 and above. Copy failures as Markdown gives a table ready for a ticket. ## Method ### 1. Reading The text is parsed as JSON and must hold `log.entries` as a list. A leading byte order mark is ignored. ### 2. By name Names are compared after lowercasing and removing everything but letters and digits. A name is a credential when it contains authorization, token, secret, password, passphrase, apikey, session, csrf, xsrf, signature, credential, privatekey, codeverifier, samlresponse, samlrequest, otp or cookie, or is exactly key, sig, sid, auth, pass, pwd, pin, ssn, cvv or cvc. `code` counts only in a URL query or form, where it is an OAuth authorization code. Names that end in type, expires, expiry, endpoint, url, uri, hint, length or format are treated as descriptive metadata, except names containing password, passwd or secret, which are always redacted. This applies to headers, query parameters, form fields, `postData.params` and keys at any depth of a JSON body. ### 3. Headers and cookies Authorization and Proxy-Authorization keep their scheme. Cookie and Set-Cookie keep each name and attribute and lose the value. The `cookies` lists of requests and responses are treated the same way. Location, Referer, Origin and Content-Location are cleaned as URLs. ### 4. URLs User and password in a URL are replaced, query parameters and OAuth or SPA fragment parameters are cleaned by name, including repeated parameters and malformed percent escapes, and the whole URL is searched for the patterns below. ### 5. Patterns in any text Supported header, query, body, comment and custom metadata text is searched for: private key blocks; AWS access key IDs; Google API keys; GitHub tokens; Stripe secret and restricted keys; Slack tokens; JSON Web Tokens; credentials after Bearer, Basic or Token; email addresses; 13 to 19 digit numbers that pass the Luhn check; and, when chosen, IPv4 addresses outside the documentation and loopback ranges. ### 6. Placeholders Each distinct value gets one placeholder for the whole file: `[TOKEN_n]`, `[PASSWORD_n]`, `[COOKIE_n]`, `[CARD_n]`, a named key such as `[AWS_KEY_n]`, `email-n@redacted.invalid`, and for IP addresses a documentation address from the three documentation ranges (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24), followed by `[IP_n]` after 762 distinct addresses. A JSON Web Token keeps its header, has its claims cleaned the same way (so an email claim is replaced), and gets `redacted-signature` as its signature. Input that looks like a placeholder is still untrusted. Running the tool again may renumber placeholders; the mapping is stable within each run. ### 7. Bodies JSON bodies are parsed, cleaned and written with the indentation they had. URL-encoded and multipart form bodies are cleaned field by field. Sensitive JSON names also apply to values inside arrays and nested objects. Malformed JSON or multipart bodies are replaced as a whole, rather than retained without inspection. Data deeper than 100 levels is refused. Other text is searched for patterns. Base64 bodies with a text, JSON, XML, JavaScript or form type are decoded, cleaned and encoded again; other Base64 bodies are binary and are kept and counted. ## Finding reference | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | N values replaced | pass | [W3C HAR](https://w3c.github.io/web-performance/specs/HAR/Overview.html) | Credentials and personal values were found and replaced | Read the file before sharing | | Nothing to replace found | info | | No credential names or known patterns matched | Read the file anyway; free text is not checked | | N failed requests | check | [RFC 9110 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) | Status 0 or 400 and above | Copy failures as Markdown for the ticket | | Binary bodies not inspected | info | | Images, fonts and archives were kept as they are | Remove the entries if a binary could hold private data | | Not a HAR file | fail | [W3C HAR](https://w3c.github.io/web-performance/specs/HAR/Overview.html) | No `log.entries` list | Export again from the Network panel; Heal it can wrap a bare `entries` list | ## Guide ### Prepare a HAR file for a support ticket 1. Record: open the developer tools, Network panel, tick Preserve log, reproduce the problem, then Save all as HAR (Chrome, Edge) or Export HAR (Firefox, Safari). 2. Drop the file here. Read What was replaced, and add your own field names under More field names if something private was missed. 3. Download the sanitized file and attach it. Paste Copy failures as Markdown into the ticket. 4. Sign out of the session you recorded, so the original cookies stop working even if the original file leaks. ### Share tokens without making them usable Keep the default JWT setting. Support can read expiry, issuer, audience and scopes, but the token has no valid signature and cannot be replayed. ### Break it cases | Case | What it adds | What it shows | | --- | --- | --- | | Token in a URL | A request with `access_token` in the query | A credential replaced in the URL | | API key header | A request with an X-API-Key header | A credential replaced in a header | | Card in a body | A JSON body with a card number | A card number replaced | | Private key in a response | A text response holding a private key block | A private key replaced | | Blocked request | A request with status 0 | A failed request in the list | | Not a HAR file | A bare `entries` object | The error and the Heal it repair | ## Use it from an agent The `har_sanitize` operation takes the HAR JSON and returns the sanitized HAR, with a warning that counts the replacements by kind. Options match the page: `cookies`, `emails`, `cards`, `ips` and `jwt`. Through the API the input goes to our server and is limited to the API's request size; use the page for files you do not want to send anywhere. See the [MCP documentation](https://docs.tamperbox.dev/mcp/). ## Limits - Names, postal addresses, phone numbers and other personal details in free text are not detected. - Binary bodies are not inspected. - Changed bodies are written out again, so Content-Length headers may not match. - Files are limited to 50 MiB in the browser. ## References - [W3C: HTTP Archive (HAR) format](https://w3c.github.io/web-performance/specs/HAR/Overview.html) - [RFC 7519: JSON Web Token](https://www.rfc-editor.org/rfc/rfc7519) - [RFC 6265: HTTP State Management Mechanism](https://www.rfc-editor.org/rfc/rfc6265) - [OWASP: Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html) --- # Hidden Character Checker How the Hidden Character Checker finds zero width, direction, look-alike, control and decomposed characters in text, counts its length four ways, and cleans it, with every rule behind each finding and how to confirm a result outside Tamperbox. Canonical: https://docs.tamperbox.dev/tools/hidden-characters/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: Text to check, pasted, typed or opened from a file of up to 200,000 characters Outputs: A verdict naming what was found, one finding per kind of character with its code point, name and positions, the text with hidden characters shown as tags, a clean copy, the four lengths and the four Unicode forms Limitations: A finding is a character present in the text, not proof of an attack; look-alike letters are only found inside Latin words or in words made of a small set of well-known look-alikes; nothing is sent anywhere The tool page is [tamperbox.dev/hidden-characters](https://tamperbox.dev/hidden-characters). It opens on the word `admin` with a zero width space (U+200B) inside it: the name a person typed, a username that looks identical to the real one and fails to log in. This page is the long version: what each finding means, how the counts differ, and how to check a result without this tool. <div class="tb-callout"><strong>Where processing happens:</strong> your text is read and cleaned in your browser. Nothing is uploaded, including text from a file you open or drop, and no server request is made for any input.</div> ## What the tool answers Two strings can look the same and not be the same. The tool answers four questions about a piece of text: 1. **Is anything in it that you cannot see?** Zero width, direction, filler, tag and control characters. 2. **Is anything in it that only looks like something else?** A no-break space for a space, a Cyrillic letter for a Latin one, a fullwidth form for an ASCII one. 3. **How long is it?** The same text has several lengths, and the one that matters depends on who is counting. 4. **Is it written in the form the receiving system expects?** An accent can be one character or two. It does not decide whether a character is harmful. A zero width non-joiner is correct in Persian and a joiner is correct inside an emoji. ## Inputs ### Text Type or paste into the box. Paste anywhere on the page outside a field also replaces the text. Input is limited to 200,000 characters. ### Files Drop a `.txt`, `.csv`, `.json`, `.md`, `.log`, `.xml` or `.html` file anywhere on the page, or use Open file. Files over 512 KiB are refused with a message. The file is read in the browser as UTF-8 and never uploaded. ## Reading the result ### Verdict and chips The verdict names how many hidden or misleading characters were found and describes the first by name and code point. The first chip is the size in characters and bytes. The other chips count each kind found and jump to the finding that explains it. ### What was found One finding per kind of character, with the code point, its Unicode name, what it does, and where it is by line and column. The status follows the risk: Fail for characters that change what is displayed or that make a blank look filled (direction overrides, fillers, tag characters, NUL, look-alike letters inside a word, broken surrogates), Check for characters that behave differently from what they look like (zero width characters, look-alike spaces, control characters, text not in composed form), and Info for notes. ### Your text with hidden characters shown The same text with each hidden character written as a tag such as ⟦U+200B⟧. Shown only when something was found. ### Clean text A copy with the repairs you tick applied. Only repairs that would change this text are listed. Use as input puts the clean text back in the box. ### Length, by every count | Count | What counts it | |---|---| | Characters | Unicode code points. Python `len()`, and most database CHAR limits | | UTF-16 units | JavaScript, Java and C# string length. An emoji counts as 2 | | UTF-8 bytes | Bytes on the wire, a VARCHAR byte limit, file names, HTTP headers | | Visible characters | What a person counts. An accent, or a family emoji built from seven code points, counts once | ### Unicode forms The text in NFC, NFD, NFKC and NFKD with the length of each, and whether it is the same as the input. ### Heal it and Break it Heal it offers to clean the text with the current choices, or to restore the input before a break. Break it adds a hidden character to your own text where it can (a zero width space inside the first word, a Cyrillic letter in place of a Latin one, a byte order mark at the start) and loads a short sample when your text cannot carry the case. Every Break it can be undone from Heal it. ## Method ### 1. Reading The text is split into code points, so an emoji is one item and a lone surrogate is one item. Each code point is classified. Neighbouring characters are used only to excuse the joiners that emoji and some scripts need. ### 2. Invisible and misleading characters | Kind | Code points | Why it matters | |---|---|---| | Zero width | U+200B, U+2060, U+2061 to U+2064, U+180E, U+FEFF inside text, U+200D outside emoji, U+200C outside non-Latin letters | Takes no space, breaks equality, search and length checks | | Byte order mark | U+FEFF at the start | Editors hide it; parsers and CSV importers see an extra character | | Direction | U+202A to U+202E, U+2066 to U+2069 (Fail); U+200E, U+200F, U+061C (Check) | Changes the display order, so what is shown is not what is stored | | Filler | U+115F, U+1160, U+3164, U+FFA0, U+2800, U+034F | Blank to the eye, not whitespace, so "not empty" checks accept it | | Tag | U+E0000 to U+E007F | Invisible and able to carry hidden text | | Control | C0 and C1 controls except tab, line feed and carriage return | NUL ends a string in C; others are acted on by terminals | | Look-alike space | U+00A0, U+1680, U+2000 to U+200A, U+202F, U+205F, U+3000, U+2028, U+2029 | Treated differently by trim(), split and equality | | Lone surrogate | U+D800 to U+DFFF alone | Not valid Unicode; encoders replace it or fail | | Replacement | U+FFFD | Data was already lost before it reached the tool | ### 3. Look-alike letters A word is a run of letters and digits. If it holds Latin letters and also Cyrillic, Greek, Armenian or Cherokee letters from a list of well-known look-alikes, each of those letters is reported with the Latin letter it resembles. A word with no Latin letter made only of look-alikes is reported as a low note, because that is how ordinary Russian or Greek words are written. The list is a short set of the common cases, not the full Unicode confusables data in [UTS #39](https://www.unicode.org/reports/tr39/). ### 4. Decomposed text and the other forms The text is compared with its NFC form ([UAX #15](https://www.unicode.org/reports/tr15/)). If they differ, a finding says how the code point count changes. A text where NFKC differs from NFC contains compatibility characters such as fullwidth letters, ligatures or superscripts. ### 5. Lengths Code points are counted with the language's own iteration, UTF-16 units with the string length, UTF-8 bytes by the size of each code point (a lone surrogate is written as U+FFFD, three bytes), and visible characters with the browser's grapheme segmentation ([UAX #29](https://www.unicode.org/reports/tr29/)). Line endings are counted as CRLF, LF and CR separately, and more than one kind is flagged as mixed. ### 6. Cleaning Each repair is optional. Invisible characters removes zero width, direction, filler, tag, control, soft hyphen and byte order mark characters, and keeps the joiners that emoji need. Spaces replaces look-alike spaces with a normal space and U+2028 and U+2029 with a line feed. Look-alike letters replaces only letters inside a Latin word. Composed form rewrites the text in NFC. Edges trims leading and trailing whitespace. The result states what each repair changed. ## Limits and interpretation - A finding is evidence of a character, not of intent. - Look-alike detection covers a small set of the commonest cases and only inside Latin words, or whole words of look-alikes. - Text from files is read as UTF-8. Text already damaged into U+FFFD cannot be repaired here. - A character your font cannot draw is not the same as a hidden character: a box or question mark is a missing glyph, which this tool does not detect. - Input is limited to 200,000 characters and files to 512 KiB. ## Finding reference | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | Zero width character | check | [UAX #9](https://www.unicode.org/reports/tr9/) | Invisible, breaks equality, search and length checks | Remove it (Clean text) | | Byte order mark at the start | check | [Unicode FAQ: BOM](https://www.unicode.org/faq/utf_bom.html#bom1) | An editor or export added it; importers see an extra character | Remove it, or save as UTF-8 without BOM | | Direction override or isolate | fail | [UAX #9](https://www.unicode.org/reports/tr9/) | What is shown is not what is stored | Remove it unless the text needs it | | Direction mark | check | [UAX #9](https://www.unicode.org/reports/tr9/) | Invisible, changes the layout of punctuation | Remove it from identifiers | | Blank filler | fail | [UTS #39](https://www.unicode.org/reports/tr39/) | Looks empty but passes a not-empty check | Remove it and treat the value as empty | | Tag character | fail | [UTS #39](https://www.unicode.org/reports/tr39/) | Can carry hidden text | Remove it | | Control character | check (NUL: fail) | [RFC 20](https://www.rfc-editor.org/rfc/rfc20) | Acted on by terminals and parsers | Remove it | | Look-alike space | check | [UAX #44](https://www.unicode.org/reports/tr44/) | trim(), split and equality treat it differently | Replace with a normal space | | Look-alike letter in a Latin word | fail | [UTS #39](https://www.unicode.org/reports/tr39/) | Reads as a Latin letter and compares unequal | Replace with the Latin letter | | Word made only of look-alikes | info | [UTS #39](https://www.unicode.org/reports/tr39/) | Normal in Cyrillic or Greek text; suspicious in a Latin context | Check where the text came from | | Not in composed form (NFC) | check | [UAX #15](https://www.unicode.org/reports/tr15/) | Equal-looking strings compare unequal | Normalize to NFC before storing or comparing | | Lone surrogate | fail | [Unicode FAQ: UTF-16](https://www.unicode.org/faq/utf_bom.html#utf16-7) | Not valid Unicode | Fix the code that split the pair | | Replacement character | check | [Unicode FAQ](https://www.unicode.org/faq/utf_bom.html) | Data was lost upstream | Get the text again, read as UTF-8 | | Stacked combining marks | info | [UAX #29](https://www.unicode.org/reports/tr29/) | Draws outside its line | Limit marks per character if layout matters | | Leading or trailing whitespace | info | | Easy to miss | Trim where the value is an identifier | ## Guide ### Find why two equal-looking values do not match 1. Paste each value in turn and compare the findings and the four lengths. 2. If one has a finding the other lacks, that character is the difference. If only the Unicode forms differ, normalize both to NFC. 3. Fix it where the value enters the system, not only where it is compared. ### Clean pasted identifiers before storing them Remove invisible characters, replace look-alike spaces and normalize to NFC for user names, email addresses, file names and keys. Keep joiners in prose, emoji and scripts that need them. ### Test that your system rejects or normalizes hidden characters Use Break it on a real value from your form: each case adds one hidden character to your text. Submit it and check that the system refuses it, cleans it, or at least stores it unchanged and shows the same length you see here. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | Zero width space | U+200B inside your first word | Zero width finding | | Cyrillic look-alike | One of your Latin letters replaced by a Cyrillic one | Look-alike letter finding | | Disguised file name | U+202E near the end of your text | Direction override finding | | No-break space | Your first space as U+00A0 | Look-alike space finding | | Byte order mark | U+FEFF at the start | Byte order mark finding | | NUL byte | U+0000 inside your first word | Control character finding | | Split accent | Your text in NFD, or a sample | Not in composed form | | Trailing spaces | Two spaces at the end | Trailing whitespace | | Blank name | U+3164 alone | Blank filler | | Hidden tag text | Two tag characters after your text | Tag character | | Emoji family | One family emoji | No findings, and four different lengths | ## Use it from an agent The same check is the `text_inspect` operation of the Tamperbox API and MCP server. It takes text, returns the counts, the findings with code point, name, line and column, and, with `clean` set to true, the cleaned text. Call it with the same input and the same limits as the page. See the [MCP documentation](https://docs.tamperbox.dev/mcp/). ## Confirm a result outside Tamperbox - Python: `[hex(ord(c)) for c in text]` lists every code point; `len(text)` and `len(text.encode())` give characters and bytes; `unicodedata.normalize("NFC", text) == text` tests the form. - JavaScript: `[...text].map(c => c.codePointAt(0).toString(16))` lists code points; `text.length` is the UTF-16 count; `new TextEncoder().encode(text).length` is the byte count; `text.normalize("NFC") === text` tests the form. - A hex dump of the file (`xxd file | head`) shows a byte order mark as `ef bb bf` at the start. ## References - [Unicode Standard Annex #15: Unicode Normalization Forms](https://www.unicode.org/reports/tr15/) - [Unicode Standard Annex #9: Unicode Bidirectional Algorithm](https://www.unicode.org/reports/tr9/) - [Unicode Technical Standard #39: Unicode Security Mechanisms](https://www.unicode.org/reports/tr39/) - [Unicode Standard Annex #29: Unicode Text Segmentation](https://www.unicode.org/reports/tr29/) - [CVE-2021-42574: bidirectional text in source code](https://nvd.nist.gov/vuln/detail/CVE-2021-42574) --- # HTTP/3 & Compression Checker What the transport checker requests, how it tests HTTP/3, measures each compression encoding and judges HSTS against the preload list's rules, what each finding means, and how to fix and verify each one. Canonical: https://docs.tamperbox.dev/tools/http3-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public HTTPS address on port 443 (an http address is upgraded by its own redirect), or response headers from curl -I to paste Outputs: A verdict with one clause per lane, three chips, the HTTP/3, compression and HSTS preload lanes with their evidence, findings worst first, and the response headers of the Brotli request Limitations: One probe location at one moment; a failed QUIC connection describes this probe, not every visitor; encoded sizes exclude headers and framing; a pasted header shows an offer, not a working connection The tool page is [tamperbox.dev/http3-checker](https://tamperbox.dev/http3-checker). It opens by checking `tamperbox.dev` live, answers in one sentence with one clause per lane, and shows the evidence under it. This page is the long version: what our server requests, every rule the page applies, what each finding means, and how to fix and verify each one. <div class="tb-callout"><strong>Where processing happens:</strong> an address is sent to the Tamperbox server, which requests the page once per compression it can ask for, attempts one HTTP/3-only connection where the probe supports it, requests the http:// form of the address and the HTTPS main domain for HSTS, and asks hstspreload.org about the main domain. Pasted response headers are read in your browser and never uploaded. History and tool-to-tool transfers remain in the browser; see Browser transfers below.</div> ## What the tool answers Three questions, one lane each, judged separately: 1. **Does the site offer HTTP/3, and does it work?** The Alt-Svc offer, and where the direct probe is available, whether a QUIC-only connection to the final HTTPS address succeeds. 2. **Does it compress its pages, and how well?** What each of `br`, `zstd` and `gzip` gets back, the encoded size of each against the uncompressed body, and whether the response declares `Vary: Accept-Encoding`. 3. **Is it ready for HSTS preload, or already preloaded?** The HSTS header on the main domain against the preload list's four rules, and the domain's status on hstspreload.org. The verdict takes the worst of the three lanes. The three chips, one per lane, scroll to the lanes. Findings under the verdict list every rule that fired, worst first. ## Inputs ### A website address `example.com`, `www.example.com/page` or `https://example.com/`. The check runs when you stop typing, or on Enter. An address without a scheme starts at `https://`. The parser refuses, with a message in the field, an address with spaces, a scheme other than `http` or `https`, an IP address, a host without a top-level domain, a port other than 80 or 443, and credentials in the address; the last two offer a repair. The fragment is dropped. Our server applies the same rules to the address and to every redirect target, and requires the host to resolve only to public addresses. ### Pasted response headers Paste the output of: ```sh curl -sI https://example.com/ ``` A paste that starts with a status line or a `Name: value` line is read in the browser. When several responses are pasted, the last one is used. The page reads `Alt-Svc`, `Content-Encoding`, `Vary` and `Strict-Transport-Security` from it. Nothing is requested, so sizes, the other encodings, the QUIC test, the http:// redirect and the preload list stay unknown, and the lanes say so. ### Files A `.txt` file dropped on the field, or chosen with Open file, is read in the browser like a paste. ### What the page does to pasted text Pasted text goes through the shared cleaner before anything runs. An address the parser accepts is kept whole; otherwise a quoted or bracketed link loses its quotes and trailing punctuation, and an email address or `mailto:` link becomes its domain. Text that fits nothing stays exactly as pasted. Typing is never rewritten; leaving the field or pressing Enter tidies what was typed the same way. Break it and Heal it loads are never cleaned. ## Reading the result ### Verdict and chips The sentence has one clause per lane: "HTTP/3 works", "HTTP/3 offered", "HTTP/3 connection failed" or "No HTTP/3 offer"; "Brotli on", "gzip on", "pages sent uncompressed" or, for a paste, the Content-Encoding found; "preloaded HSTS", "HSTS preload pending", "ready for HSTS preload", "not eligible for HSTS preload" or "no HSTS". The detail names the final address and its status, or says the result came from pasted headers. The chips repeat the three lane states: the HTTP/3 state, "n of 3 encodings" or "Not compressed", and "Preload ready", "Preload not ready" or "Preloaded". ### Protocol, compression, preload Three lanes side by side. The HTTP/3 lane shows the state in one word (Works, Advertised, Failing, Not offered), the Alt-Svc line as sent, and for how long browsers remember the offer. The compression lane lists what each Accept-Encoding got back with its encoded size, and the identity body size. The HSTS preload lane shows the preload status, the header as sent, the four submission checks with their state, a note on the list's answer, and, when the header is not eligible, the line to send with a Copy button. ### Findings Every rule that fired, worst first; two or more passes fold into one line. ### Response headers Behind a disclosure, the full headers of the Brotli request (or the pasted headers), with the four that matter labelled: Alt-Svc, Content-Encoding, Vary and Strict-Transport-Security. ### History Every Break it and Heal it change, newest first, with what it replaced. Revert undoes the newest change; Reset input returns to what you entered. ### Take it further For a live result with a main domain, the [Redirect Checker](https://docs.tamperbox.dev/tools/redirect-checker/) link receives its `http://` root address to trace the redirect required by preload rules. A separate button opens the [Unix Timestamp Converter](https://docs.tamperbox.dev/tools/unix-timestamp/) when the result has a finite, positive HSTS max-age. It adds that duration to the current time when the result is rendered. This illustrates the duration; it is not the expiry of a particular browser’s stored HSTS policy. The timestamp button uses a one-time message to a new same-origin tab, with no input in the URL or browser storage. Keep the source tab open until the transfer completes. A blocked popup or a transfer taking over 30 seconds produces a message; copy the value if needed. The Redirect Checker link uses the browser transfer described below. ### Browser transfers Explicit tool links temporarily place the transferred input in browser `sessionStorage`. The URL fragment carries a random token, not the input. The receiving page accepts that token once, for its destination path and for less than one minute, then removes it from the address. A same-origin browser channel can complete a transfer into another tab. Ordinary documentation links do not transfer input. When browser storage is unavailable, navigation still works but the input may need to be pasted again. ## Method The rules, in the order they are applied. The analysis is one function, `assessTransport` in the shared HTTP checks library, that the page, the server and the MCP operation run on the same evidence. ### What our server requests With the direct probe available, our server runs one GET per encoding, `br`, `zstd`, `gzip` and `identity`, two at a time, each with a 4 second connect timeout and an 8 second request limit, within 22 seconds for the whole check. Automatic redirects and content decoding are off; the probe follows up to five redirects itself, revalidating each target, and refuses a loop. Each body is counted as received, without decoding, up to 2 MiB. Then one HEAD request is sent over HTTP/3 only to the final HTTPS address, with no fallback. Separately, the server requests `https://` on the registrable domain (the main domain: `example.com` for `www.example.com`) for its HSTS header, requests the `http://` form of the final address to see its redirect, and asks `https://hstspreload.org/api/v2/status` about the registrable domain. Without the direct probe, the server fetches the page once per encoding through its ordinary client, which decodes bodies, so only decoded sizes are known and HTTP/3 is not tested. Headers shown in full are those of the `br` request. ### HTTP/3 - The Alt-Svc header is parsed per [RFC 7838 Section 3](https://www.rfc-editor.org/rfc/rfc7838#section-3): a list of `protocol="authority"` entries, each with an optional `ma` parameter. An entry for `h3` or a draft such as `h3-29` is an HTTP/3 offer. Per [Section 3.1](https://www.rfc-editor.org/rfc/rfc7838#section-3.1), an entry without `ma` is remembered for 86400 seconds, and the value `clear` means no alternatives. - With a direct test, **HTTP/3 works** (PASS) when the response really arrived over HTTP version 3, with the time taken; **HTTP/3 connection failed** (FAIL) when the attempt errored or the answer came back on another version. The test runs whether or not Alt-Svc offers h3, so a server that answers over QUIC shows as working even without an offer. - Without a direct test, **HTTP/3 advertised** (PASS) when Alt-Svc offers h3, with the authority and the duration; **No HTTP/3 advertisement** (CHECK) otherwise, which does not prove the server lacks HTTP/3. - **Alt-Svc remembered for n minutes** (INFO) when `ma` is under 86400: browsers forget the offer quickly and start each visit on HTTP/2. - **No HTTP/2** (CHECK) when the first successful transfer used HTTP/1.1. The HTTP/3 lane is PASS for works or advertised, FAIL for a failed connection, CHECK otherwise. ### Compression An encoding counts as applied when the response to that Accept-Encoding carries a Content-Encoding other than `identity`, following [RFC 9110 Section 8.4](https://www.rfc-editor.org/rfc/rfc9110#section-8.4) and [Section 12.5.3](https://www.rfc-editor.org/rfc/rfc9110#section-12.5.3). Savings compare each encoded body with the identity body of a separate request. | Condition | Finding | Status | | --- | --- | --- | | No request got an encoded response | Not compressed, with the uncompressed size when known | FAIL | | Something applied, but the `br` request did not get `br` back | No Brotli, naming what applied | CHECK | | `br` applied, sizes known | Brotli saves n% | PASS | | `br` applied, sizes unknown | Brotli compression observed | PASS | | `zstd` applied | Zstandard offered | PASS | | A compressed response without `Vary: Accept-Encoding` or `Vary: *` | No Vary: Accept-Encoding | CHECK | | Pasted headers with Content-Encoding | Compressed with (encoding) | PASS | | Pasted headers without Content-Encoding | No Content-Encoding in the pasted headers | INFO | The Vary rule follows [RFC 9110 Section 12.5.5](https://www.rfc-editor.org/rfc/rfc9110#section-12.5.5): "An origin server SHOULD send a Vary header field when its algorithm for selecting a representation varies based on aspects of the request message other than the method and target URI". The finding says a shared cache could reuse an incompatible encoding; it is not evidence that one did. The compression lane is PASS with Brotli, CHECK with another encoding only, FAIL with none; for a paste it is PASS with an encoding and INFO without. ### HSTS and the preload list The HSTS header is parsed per [RFC 6797 Section 6.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1): `max-age` (required, whole seconds), `includeSubDomains` and `preload`, with unknown directives noted. The header used is the main domain's; if that request failed or carried no header, the final page's header is used. The four submission checks follow the preload list's own rules, which are Chromium's policy ([hstspreload.org submission requirements](https://hstspreload.org/#submission-requirements)), not an RFC: | Check | Rule | | --- | --- | | HTTP redirects to HTTPS on the same host | The `http://` form of the final address answers with a Location on `https://` and the same host name; not checked when that request fails | | max-age at least one year (31536000) | `max-age` of 31536000 or more | | includeSubDomains | The directive is present | | preload directive | The directive is present | The header is eligible when no check is false. The list's answer decides the finding: **(domain) is preloaded** or **Preloaded via (parent)** (PASS) when hstspreload.org reports the domain or a parent entry, including a top-level domain such as `dev`; **Preload submission pending** (INFO); **Ready to preload** or **Ready to preload, not listed** (INFO) when the header is eligible; **No HSTS header** (CHECK); **Not eligible for preload** (CHECK) with the missing checks named. If the list service does not answer, the status is unavailable, never absent. Inherited coverage protects the domain even when its own header fails the individual checks, which are still shown for reference. The lane is PASS when preloaded or eligible, INFO when pending, CHECK otherwise. ### Heal it For pasted headers only: **Preview an HTTP/3 Alt-Svc offer** adds `alt-svc: h3=":443"; ma=86400` when none is present, and **Make HSTS preload-ready** replaces the HSTS header with `max-age=63072000; includeSubDomains; preload`. Both edit the pasted example; publishing Alt-Svc still needs a working HTTP/3 service, and preload settings need HTTPS on every subdomain. ## Standards and conformance The checker observes what one set of requests from our server received and judges it with the rules above. It is not a browser: it does not switch to an alternative service after seeing Alt-Svc, does not decode bodies in the direct measurement, and does not keep HSTS state. ### RFC 7838: HTTP Alternative Services [RFC 7838](https://www.rfc-editor.org/rfc/rfc7838) is a Proposed Standard (April 2016). [Section 3](https://www.rfc-editor.org/rfc/rfc7838#section-3) gives the header syntax and [Section 3.1](https://www.rfc-editor.org/rfc/rfc7838#section-3.1) the `ma` parameter and its 24 hour default: "When this parameter is omitted, the default is 24 hours". The tool parses the header, reports the h3 offer, its authority and its lifetime, and notes a lifetime under a day. It does not connect to the advertised authority; the direct test goes to the final HTTPS origin on port 443 only. ### RFC 9114 and RFC 9000: HTTP/3 over QUIC [RFC 9114](https://www.rfc-editor.org/rfc/rfc9114) (HTTP/3) and [RFC 9000](https://www.rfc-editor.org/rfc/rfc9000) (QUIC) are Proposed Standards. [RFC 9114 Section 3.1](https://www.rfc-editor.org/rfc/rfc9114#section-3.1) describes discovery through Alt-Svc with the `h3` identifier; the direct test is a single HEAD request that succeeds only when the response was carried on HTTP version 3. The tool does not test 0-RTT, connection migration or any QUIC version detail. ### RFC 9113: HTTP/2 [RFC 9113](https://www.rfc-editor.org/rfc/rfc9113) is a Proposed Standard and obsoletes [RFC 7540](https://www.rfc-editor.org/rfc/rfc7540). HTTP/2 is inferred from the version of the first successful transfer; the tool does not inspect ALPN directly and the TLS version is not reported here. ### RFC 9110: content coding and Vary [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110) is an Internet Standard (STD 97). [Section 8.4](https://www.rfc-editor.org/rfc/rfc9110#section-8.4) defines Content-Encoding and the coding names registered at IANA, [Section 12.5.3](https://www.rfc-editor.org/rfc/rfc9110#section-12.5.3) Accept-Encoding, and [Section 12.5.5](https://www.rfc-editor.org/rfc/rfc9110#section-12.5.5) Vary. The codings themselves are specified by [RFC 7932](https://www.rfc-editor.org/rfc/rfc7932) (Brotli), [RFC 8878](https://www.rfc-editor.org/rfc/rfc8878) (Zstandard, which obsoletes [RFC 8478](https://www.rfc-editor.org/rfc/rfc8478)) and [RFC 1952](https://www.rfc-editor.org/rfc/rfc1952) (gzip); the tool reads the coding names and sizes and never decodes. ### RFC 6797: HSTS [RFC 6797](https://www.rfc-editor.org/rfc/rfc6797) is a Proposed Standard (November 2012). [Section 6.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1) defines the header and its directives; [Section 6.1.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1.1) requires `max-age`: "The REQUIRED "max-age" directive specifies the number of seconds". The `preload` directive is not part of RFC 6797; it is the preload list's own token. The tool parses the header as the RFC describes and judges it by the list's rules, which are stricter than the RFC (the RFC sets no minimum lifetime). ### Where the tool stops - Only the final HTTPS origin on port 443 is tested for QUIC; alternative authorities and ports in Alt-Svc are not probed. - Sizes are encoded response-body bytes from separate requests; dynamic pages can differ between them. - The preload list answer is hstspreload.org's; browsers ship their own copy with a delay. - Inherited preload coverage is reported as a pass even when the domain's own header is not eligible. ## Finding reference ### HTTP/3 and HTTP/2 | Finding | Status | Rule | What it means | Fix | | --- | --- | --- | --- | --- | | HTTP/3 works | PASS | Direct HEAD over QUIC answered on version 3 | Browsers switch to QUIC after the first response advertises it | Nothing; keep Alt-Svc published | | HTTP/3 advertised | PASS | Alt-Svc offers h3; no direct test | The offer is seen; whether QUIC connects is unknown | Nothing on the page; test from the command line | | HTTP/3 connection failed | FAIL | Direct test errored or fell to another version | Browsers try QUIC, wait, and fall back to HTTP/2 | Open UDP 443 at the firewall or security group; enable HTTP/3 at the CDN; build the server with QUIC | | No HTTP/3 advertisement | CHECK | No h3 in Alt-Svc, no direct result | Not proof of absence | Enable HTTP/3 and publish Alt-Svc | | Alt-Svc remembered for n minutes | INFO | `ma` under 86400 | Each visit starts on HTTP/2 | Set `ma=86400` or longer | | No HTTP/2 | CHECK | First transfer on HTTP/1.1 | Requests queue on six connections | Enable HTTP/2 on the server or proxy | ### Compression | Finding | Status | Rule | What it means | Fix | | --- | --- | --- | --- | --- | | Not compressed | FAIL | No encoding applied | HTML travels uncompressed; Brotli or gzip usually cut it by 70 to 85% | Enable compression for text types at the server or CDN | | No Brotli | CHECK | `br` not returned for the `br` request | Brotli is usually 15 to 25% smaller than gzip for HTML | Enable Brotli; every current browser accepts it | | Brotli saves n% | PASS | `br` applied, sizes known | The saving against the identity body | Nothing | | Brotli compression observed | PASS | `br` applied, sizes unknown (fallback measurement) | Compression works; the saving is not measured | Nothing | | Zstandard offered | PASS | `zstd` applied | Chrome and Firefox accept it | Nothing | | No Vary: Accept-Encoding | CHECK | Compressed response without the Vary value | A shared cache could serve the wrong encoding | Add `Vary: Accept-Encoding` at the origin; check the proxy does not strip it | | Compressed with (encoding) | PASS | Pasted Content-Encoding | The response was encoded | Nothing; sizes need a live check | | No Content-Encoding in the pasted headers | INFO | Pasted, no Content-Encoding | Either not compressed or not requested | Run a live check | ### HSTS and preload | Finding | Status | Rule | What it means | Fix | | --- | --- | --- | --- | --- | | (domain) is preloaded, Preloaded via (parent) | PASS | hstspreload.org reports the domain or a parent | Browsers enforce HTTPS before the first visit | Nothing; keep the header | | Preload submission pending | INFO | Status pending | Waiting for a browser release | Keep the header in place | | Ready to preload, not listed | INFO | Header eligible, status none | Submission is possible; it is a commitment that takes months to undo | Confirm every subdomain serves HTTPS, then submit | | No HSTS header | CHECK | No Strict-Transport-Security | The first request can be made in plain text | Send the header on the main domain | | Not eligible for preload | CHECK | One or more checks false | The missing checks are named | Send `max-age=63072000; includeSubDomains; preload` on the main domain and redirect http:// to https:// on the same host | ## Guide ### HTTP/3 connection failed 1. Read the error in the lane: a timeout usually means UDP 443 is blocked by a firewall or security group; "did not use HTTP/3" means the server answered but on another version. 2. At a CDN, switch HTTP/3 on in its settings. On your own server, build or configure QUIC (nginx 1.25 with `listen 443 quic;`, Caddy on by default) and open UDP 443. 3. Confirm from the command line, then check again: ```sh curl -sI --http3-only https://example.com/ | head -1 ``` ### No HTTP/3 offer 1. Enable HTTP/3 as above. 2. Publish the offer on every HTTPS response: `Alt-Svc: h3=":443"; ma=86400`. 3. Check again; the lane should read Advertised or Works, and the INFO about a short `ma` should not appear. ### Not compressed, or gzip only 1. Enable compression for text types (`text/html`, `text/css`, `application/javascript`, `application/json`, `image/svg+xml`) at the server or CDN; a CDN may have it off while the origin compresses, or the reverse. 2. Prefer Brotli with gzip as the fallback; add Zstandard where the server supports it. 3. Confirm each encoding and the sizes: ```sh for e in br zstd gzip identity; do printf '%s ' "$e"; curl -so /dev/null -H "Accept-Encoding: $e" -w '%{content_type} %{size_download}\n' https://example.com/; done ``` ### No Vary: Accept-Encoding 1. Add `Vary: Accept-Encoding` to compressed responses at the origin. 2. Check the proxy or CDN in front of it does not drop the header. 3. Check again; the CHECK disappears. ### Not eligible for preload 1. Read the four checks in the lane; the missing ones are named in the finding. 2. Make `http://` on the main domain redirect to `https://` on the same host with 301 or 308 (the Redirect Checker link under Take it further traces it). 3. Send `Strict-Transport-Security: max-age=63072000; includeSubDomains; preload` on the main domain, only after confirming that every subdomain serves HTTPS: preloading applies to all of them and removal takes months to reach browsers. 4. Check again, then submit at hstspreload.org when the lane reads Ready. Confirm the header with: ```sh curl -sI https://example.com/ | grep -i strict-transport-security ``` ### Reading pasted headers Paste `curl -sI` output to check the offer, the encoding and the HSTS header of a response you already have. The lanes say what a live check would add. Heal it previews an Alt-Svc offer and a preload-ready HSTS header on the pasted text. ### Break it cases | Case | What loads | What it shows | | --- | --- | --- | | Drop Alt-Svc | Your result's headers (or the sample's) as text, without Alt-Svc | The CHECK for no offer, and the Heal it preview | | gzip only, no HTTP/3 | `legacy.harbor-supply.example` | No offer, gzip without Brotli, no HSTS on the host | | Not compressed | `plain.harbor-supply.example` | The FAIL for uncompressed pages | | Alt-Svc for 5 minutes | `quic.harbor-supply.example` | The INFO for a short `ma` | | Ready to preload | `preload.harbor-supply.example` | Brotli, Zstandard, an eligible header, not yet listed | The reserved names are answered in the browser and never requested; the sample's compression sizes are decoded sizes only. ## Worked example The page opens on `tamperbox.dev`, checked live by our server when the page loads. Read the result top down: the verdict gives one clause per lane; the chips repeat the lane states; the HTTP/3 lane shows the Alt-Svc line as sent and, when the direct probe ran, whether the QUIC-only HEAD request succeeded and how long it took; the compression lane lists what each Accept-Encoding got back with its encoded size against the identity body; the HSTS preload lane shows the header on the main domain, the four checks and the list's answer, which for a `.dev` name is inherited from the top-level domain's entry. The exact header values, sizes and timings are live evidence and change with the site's configuration and the moment of the check, so they are not reproduced here. Replace the address in the box to check your own site, or press a Break it case to see each state on the reserved sample. ## For agents The Tamperbox MCP server exposes two MCP tools: use `search` to inspect the catalog and schema, then use `execute` to call `POST /v1/tools/http3_checker` through `tamperbox.request`. Its required `url` must identify a public host; use `https://` when testing HTTP/3. The result carries `status`, `http3` (`advertised`, `tested`, `ok`, `timeMs`, `error`), `alpn`, `encodings` (one row per Accept-Encoding with `encoding`, `bytes` and `timeMs`), `headers`, `hsts` (`header`, `httpRedirect`, `apex`, `apexHeader`) and `preload` (`domain`, `status`), plus warnings and provenance. Apply the rules in [Method](#method) to read it, and keep these warnings with any conclusion: - A failed QUIC connection describes this probe's path to the server, not every visitor's. - An Alt-Svc offer is a claim; only a tested connection is evidence that HTTP/3 works. - Sizes come from separate requests and exclude headers and framing; `bytes: null` means the size is unknown, not zero. - A preload status of `unavailable` means the list could not be asked, not that the domain is absent. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the address travels. ## Limits - One probe location at one moment. A failed HTTP/3 connection, a slow transfer or a missing header can be specific to this path. - The direct test sends one HEAD over HTTP/3 only to the final HTTPS origin; alternate hosts and ports from Alt-Svc are not probed. - Encoded sizes exclude HTTP headers, TLS and QUIC framing and retransmissions; transfers above 2 MiB or interrupted transfers have unknown complete sizes; separate requests can return different content. - Without the direct probe, only advertisement and encoding headers are reported, and byte counts stay unknown. - The TLS version is not reported here; HTTP/2 is inferred from the transfer that succeeded. - Preload coverage is reported from hstspreload.org; a domain can inherit coverage from a parent entry even without its own header. - A missing `Vary: Accept-Encoding` is a cache-compatibility warning, not proof of a wrong response. - History is a browser interaction record, not server monitoring. Explicit tool links use temporary browser storage as described in [Browser transfers](#browser-transfers). ## References - [RFC 7838, HTTP Alternative Services](https://www.rfc-editor.org/rfc/rfc7838). Proposed Standard, April 2016. Sections used: [3](https://www.rfc-editor.org/rfc/rfc7838#section-3) and [3.1](https://www.rfc-editor.org/rfc/rfc7838#section-3.1). - [RFC 9114, HTTP/3](https://www.rfc-editor.org/rfc/rfc9114). Proposed Standard, June 2022. Section used: [3.1](https://www.rfc-editor.org/rfc/rfc9114#section-3.1). - [RFC 9000, QUIC: A UDP-Based Multiplexed and Secure Transport](https://www.rfc-editor.org/rfc/rfc9000). Proposed Standard, May 2021. Used as the transport the direct test requires. - [RFC 9113, HTTP/2](https://www.rfc-editor.org/rfc/rfc9113). Proposed Standard, June 2022; obsoletes [RFC 7540](https://www.rfc-editor.org/rfc/rfc7540) and [RFC 8740](https://www.rfc-editor.org/rfc/rfc8740). - [RFC 9110, HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110). Internet Standard, STD 97, June 2022. Sections used: [8.4](https://www.rfc-editor.org/rfc/rfc9110#section-8.4), [12.5.3](https://www.rfc-editor.org/rfc/rfc9110#section-12.5.3) and [12.5.5](https://www.rfc-editor.org/rfc/rfc9110#section-12.5.5). - [RFC 6797, HTTP Strict Transport Security (HSTS)](https://www.rfc-editor.org/rfc/rfc6797). Proposed Standard, November 2012. Sections used: [6.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1) and [6.1.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1.1). - [HSTS preload list submission requirements](https://hstspreload.org/#submission-requirements). Chromium project policy; the `preload` directive and the four checks come from here, not from an RFC. - [RFC 7932, Brotli Compressed Data Format](https://www.rfc-editor.org/rfc/rfc7932). Informational, July 2016; updated by [RFC 9841](https://www.rfc-editor.org/rfc/rfc9841). - [RFC 8878, Zstandard Compression and the 'application/zstd' Media Type](https://www.rfc-editor.org/rfc/rfc8878). Informational, February 2021; obsoletes [RFC 8478](https://www.rfc-editor.org/rfc/rfc8478); updated by [RFC 9659](https://www.rfc-editor.org/rfc/rfc9659). - [RFC 1952, GZIP file format specification version 4.3](https://www.rfc-editor.org/rfc/rfc1952). Informational, May 1996. - [IANA HTTP Content Coding Registry](https://www.iana.org/assignments/http-parameters/http-parameters.xhtml#content-coding). The names `br`, `zstd`, `gzip` and `identity` the tool requests. --- # JSON to YAML Converter How Tamperbox converts JSON to YAML live in the browser, which hostile or ambiguous inputs it refuses, and how to verify semantic round trips. Canonical: https://docs.tamperbox.dev/tools/json-to-yaml/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A JSON value pasted, typed, dropped or opened as a local file Outputs: YAML representing the same JSON objects, arrays and scalar values; Findings for validity, complexity and interoperability boundaries Limitations: The converter preserves parsed data, not whitespace, quote style or object layout; It does not validate an application schema or predict every YAML loader's schema choices; Input is limited to 1,000,000 characters, 80 levels and 100,000 values The tool page is [tamperbox.dev/json-to-yaml](https://tamperbox.dev/json-to-yaml). It opens with a synthetic QA test-suite object and converts it immediately. This guide explains the parser boundary, the live-update behavior, every refusal, how the reverse handoff works and how to test that a conversion kept the intended data. <div class="tb-callout"><strong>Where processing happens:</strong> the source is sent only to a Web Worker in the current browser tab. Conversion does not upload the source or interpret it as code. Explicit reverse-conversion navigation temporarily stores the output in tab-scoped session storage for the handoff; ordinary conversion does not persist it. The worker returns converted text and bounded counts to the page.</div> ## What the tool answers The page answers four questions in task order. First, is the source unambiguous JSON under the interoperability rules used by the converter? Second, what JSON kind and how many values or containers did the parser read? Third, can that tree be represented with the JSON-compatible YAML schema without changing its values? Fourth, what should a QA engineer test before the YAML becomes a fixture, configuration file or deployment input? The verdict is about the parsed data model. “Converted valid JSON to YAML” does not mean an application accepts the document. It does not apply JSON Schema, an OpenAPI schema or a product configuration schema. It also does not promise that a YAML loader using YAML 1.1 implicit typing will interpret every plain scalar like this converter's YAML 1.2-oriented JSON schema. ## Inputs ### Typed or pasted JSON The field accepts any JSON value: object, array, string, number, boolean or null. Editing is live. An input event clears the old output immediately, waits 120 milliseconds to avoid parsing every intermediate keystroke, then sends the current source to the worker. Worker results carry a revision number and are ignored after a newer conversion request starts. The current implementation advances that revision when it dispatches the request, rather than on the initial keystroke; see the timing limitation below. Pasting in the field or elsewhere on the page replaces the source. The text is not “cleaned” into a different shape because punctuation is meaningful JSON. Clear empties the source, output and cards. Empty input is a neutral state, not an invalid document. ### Dropped or opened files The shared drop zone accepts `.json`, `application/json` and plain-text files. The browser reads the file as text. A file above 1,000,000 bytes is refused before conversion. The file name may appear in the field hint; the bytes never leave the browser. ### Reverse-conversion handoff Take it further sends the current YAML output to the YAML to JSON page. The transfer uses a one-use random token, session storage and same-origin BroadcastChannel communication, with a 60-second validity window. The source is never placed in a query string or durable storage. The destination consumes the value once and removes the token from its address. ### Input limits | Boundary | Limit | Why it exists | | --- | ---: | --- | | Source text | 1,000,000 characters | Bounds memory, worker messages and parsing time | | Nesting | 80 levels | Prevents hostile recursion and impractical fixtures | | Tree size | 100,000 values and containers | Bounds traversal and YAML generation | | Integer interoperability | −(2<sup>53</sup>−1) through 2<sup>53</sup>−1 | Prevents silent precision changes in JavaScript and common JSON consumers | | Worker freshness | Current dispatched revision only | Rejects responses superseded by a newer dispatched request | ## Reading the result ### Verdict and checks A successful verdict names both formats and states that the represented data is unchanged. The checks name valid JSON and JSON-model preservation; the validity detail and a chip give the bounded node count. A failed verdict clears the output before showing the reason, so Copy result cannot accidentally return the previous valid conversion. Heal it then offers the newest source that converted successfully. ### Findings The findings separate syntax from interoperability. Valid syntax receives a Pass. The data-model check receives a Pass after the complete tree walk. A parser refusal receives one Fail with a safe message; it never echoes private input. The page folds multiple passing rows into one disclosure so problems remain first. ### Converted output Output uses two-space indentation and a line-width preference of 100 characters. The emitter uses the JSON-compatible YAML schema and disables references, so repeated objects are written as repeated values rather than synthesized anchors. That makes the output predictable for test fixtures but can make a document larger. ### History and reverse conversion Break it replacements and Heal it repairs are logged newest first. Revert restores the input before the latest change. Reset returns to the first input in that history. Ordinary typing starts a new history because it is a new source, not an automated repair. The reverse link appears only for a valid current output. ## Method ### Strict JSON parsing The source first passes the platform JSON parser. Then a JSON-token parser checks the same source inside a wrapper object. This second pass detects duplicate member names and integers that cannot be represented safely. A converter must not silently keep the first or last duplicate because different downstream parsers choose differently. [RFC 8259 section 4](https://www.rfc-editor.org/rfc/rfc8259#section-4) says object names “SHOULD be unique.” The tool treats that interoperability recommendation as a refusal: the intended value cannot be inferred safely. Section 4 also explains that receiver behavior is unpredictable when names are not unique. The stricter choice is deliberate and appears in the page limits. ### Numeric interoperability [RFC 8259 section 6](https://www.rfc-editor.org/rfc/rfc8259#section-6) permits implementations to set number range and precision limits. It identifies integers in the binary64 exact range as interoperable. The tree walk therefore accepts finite numbers and rejects an integer outside the safe range with “A number is too large to convert safely. Quote it as text.” Quoting identifiers is not a workaround that changes nothing: it intentionally makes the identifier a string, which is usually the correct contract for account numbers, database IDs and long request IDs. ### Complexity walk The parsed value is traversed iteratively. Each stack item carries depth. More than 80 levels or 100,000 visited nodes stops before YAML emission. The iterative walk avoids using the JavaScript call stack for attacker-controlled nesting. Primitive values count because a flat array with a million strings can be as expensive as a deep tree. ### YAML emission The emitter receives only the checked value. It uses the JSON schema described by [YAML 1.2.2 section 10.2](https://yaml.org/spec/1.2.2/#102-json-schema), disables references and selects two-space indentation. YAML mappings represent JSON objects, sequences represent arrays, and JSON strings, finite numbers, booleans and null use compatible scalar forms. Key order follows the parsed object's enumeration order as an implementation convenience, not a semantic promise. JSON object order does not establish application meaning. A consumer that depends on order needs an array or an explicit order field. ### Live rendering and stale-result control An input edit clears the visible output and schedules conversion. Dispatch increments the revision, and the worker echoes it. The page ignores a response whose revision no longer matches. This guards requests already superseded by another dispatched request. It does not invalidate the earlier revision during the preceding debounce interval or on the empty-input path. Wait for conversion to settle before copying or following the reverse link; a matching revision alone does not prove that the source has remained unchanged since dispatch. ## Standards and conformance ### RFC 8259 | Sections | Applied here | Deliberate boundary | | --- | --- | --- | | [3 Values](https://www.rfc-editor.org/rfc/rfc8259#section-3) | Accepts every JSON value at the root | Does not require an object or array | | [4 Objects](https://www.rfc-editor.org/rfc/rfc8259#section-4) | Parses objects and refuses repeated names | Stricter than `SHOULD` for deterministic conversion | | [5 Arrays](https://www.rfc-editor.org/rfc/rfc8259#section-5) | Preserves element order and mixed value kinds | Does not apply an item schema | | [6 Numbers](https://www.rfc-editor.org/rfc/rfc8259#section-6) | Requires finite, safely representable integers | Does not preserve source exponent spelling | | [8 Strings](https://www.rfc-editor.org/rfc/rfc8259#section-8) | Uses the platform Unicode JSON parser | Does not normalize Unicode | ### YAML 1.2.2 The output targets the [JSON schema](https://yaml.org/spec/1.2.2/#102-json-schema), not the core schema and not YAML 1.1. It uses block mappings and sequences chosen by the emitter. The tool does not claim byte-level canonical YAML, preserve comments or attach application tags. The YAML specification defines a representation graph, serialization tree and presentation stream as distinct levels; this conversion promises the compatible representation, not the original presentation. ## Finding reference ### Refusals | Finding | Status | Meaning | Fix | | --- | --- | --- | --- | | Invalid JSON | Fail | Syntax is incomplete or a duplicate/unsafe value made intent ambiguous | Correct the source or restore the last valid JSON | | Input above limit | Fail | The browser worker budget would be exceeded | Split the artifact or remove unrelated data | | Document too complex | Fail | Depth or node count exceeded its bound | Flatten nesting or split the fixture | | Unsafe integer | Fail | A common JSON consumer may round the identifier | Quote it as a string and update the schema | ### Successful evidence | Finding | Status | What it proves | What it does not prove | | --- | --- | --- | --- | | Valid JSON | Pass | The complete source parsed under the strict checks | The application schema accepts it | | JSON data model preserved | Pass | The emitter received the checked tree | Every YAML loader chooses identical schemas | | Node count | Pass | The bounded walk completed | The document is small enough for every consumer | ## Guide ### Convert a fixture safely 1. Paste or open the JSON. Wait for the valid verdict; conversion normally follows the edit after 120 milliseconds. 2. Use Break it → Duplicate key. Confirm the tool clears the YAML rather than choosing one value. Heal it restores the last valid source. 3. Use Break it → Unsafe integer. Decide whether that field is an identifier. If so, quote it in JSON and require a string in the schema. 4. Read the YAML once for application conventions such as required document markers or key order rules. These are outside the data-model conversion. 5. Open “Convert this YAML back to JSON.” Deep-compare the parsed JSON values. 6. Run the application's own schema validator and tests on the exported YAML. ### Check independently With Node.js and a YAML package already approved by your project, parse both ends and compare values rather than text: ```js import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { load } from 'js-yaml'; const json = JSON.parse(readFileSync('fixture.json', 'utf8')); const yaml = load(readFileSync('fixture.yaml', 'utf8')); assert.deepEqual(yaml, json); ``` This command tests your chosen loader, which is valuable because schemas and duplicate-key policies vary. Run it in the project's locked dependency environment, not by installing an unreviewed global package. ### Break it and manual edge cases | Case | Input property | Expected result | | --- | --- | --- | | Duplicate key | Two `role` members | Refused; neither value is selected | | Unsafe integer | `9007199254740993` | Refused; quote the identifier intentionally | | Truncated JSON | An unclosed array | Refused; no stale YAML remains | | Excessive depth | More than 80 nested arrays | Refused before emission | | Empty source | Whitespace only | Neutral empty state | ## Worked example The synthetic opening object describes a checkout suite with two cases. Each case has a name and expected HTTP status, and the suite has an enabled boolean. The YAML mapping keeps the suite name, the sequence keeps case order, each nested mapping keeps its fields, numeric statuses remain numbers and the boolean remains a boolean. No real endpoint, credential or customer data appears. Changing `expected` from `401` to `403` clears the old YAML immediately, then rewrites that scalar after the debounce. Removing the closing brace clears the output and produces a refusal. Restoring it creates a fresh result. Check each completed result against the current source. Rapid edits while a worker is still running are subject to the timing limitation below. ## For agents The browser page is the private-input surface. Remote automation may call `json_to_yaml` through the Tamperbox API or MCP with an `application/json` text artifact and an optional indentation from 1 through 8. A remote call transmits the artifact to Tamperbox infrastructure; preserve that distinction when advising a user with secrets. An agent should retain the warnings and provenance, avoid claiming that conversion validates a schema, and test hostile cases before recommending generated fixtures. It should never “repair” a duplicate by choosing the value that looks safer. Ask which value the producer intended or reject the source. ## Limits ### Timing and handoff boundaries Revision checks begin at dispatch, not at each edit. An earlier worker response can arrive during the 120-millisecond debounce or after Clear and repaint an earlier result. Do not rely on this version for a strict no-stale-output guarantee; wait for the current conversion and compare the output with the source before using it. Reverse handoff temporarily uses session storage and a random URL fragment, with expiry and one-use consumption. ### Format boundaries The converter does not preserve JSON whitespace, exponent notation, escape spelling or member order as a contract. It does not infer YAML tags, comments or anchors. It does not validate Kubernetes, GitHub Actions, Docker Compose, OpenAPI or another application schema. It cannot prove how a YAML 1.1 loader interprets plain scalars. Processing is local on the page, but a user who follows a remote API or MCP example changes that privacy boundary. ## References - [RFC 8259](https://www.rfc-editor.org/rfc/rfc8259), especially [values](https://www.rfc-editor.org/rfc/rfc8259#section-3), [objects](https://www.rfc-editor.org/rfc/rfc8259#section-4), [arrays](https://www.rfc-editor.org/rfc/rfc8259#section-5), [numbers](https://www.rfc-editor.org/rfc/rfc8259#section-6) and [strings](https://www.rfc-editor.org/rfc/rfc8259#section-8). Internet Standard. - [YAML 1.2.2](https://yaml.org/spec/1.2.2/), especially the [representation model](https://yaml.org/spec/1.2.2/#chapter-3-processes-and-models) and [JSON schema](https://yaml.org/spec/1.2.2/#102-json-schema). Current YAML language specification used for the output boundary. --- # JWT Decoder & Verifier What the JWT decoder reads from a token, every rule it applies to the header, the signature and the claims, what each finding means for the application that receives the token, and how to fix and verify each one. Canonical: https://docs.tamperbox.dev/tools/jwt/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: A three-part signed JWT (a Bearer prefix is removed), and, for signature verification, the HMAC secret or the public JWK or SPKI PEM that matches the token's algorithm Outputs: A verdict with PASS, CHECK and FAIL chips for the signature and each registered claim, the header and payload as editable tables or JSON, the rebuilt token with its signature state, History and Take it further links for the time claims Limitations: Decoding proves readability, not trust; a signature match proves only that this key verifies these bytes; JWE, crit headers and unencoded payloads are not verified; no key is ever fetched from a token The tool page is [tamperbox.dev/jwt](https://tamperbox.dev/jwt). It opens on a synthetic token signed in your tab, answers in one sentence whether that token would be rejected and why, and shows the header, the claims and the rebuilt token under it. This page is the long version: what the page reads, every rule it applies, what each finding means for the application that receives the token, and how to fix and verify each one. <div class="tb-callout"><strong>Where processing happens:</strong> everything runs in your browser. The token, the key and the expected values are read locally; signatures are checked with the browser's Web Crypto implementation; the `jku` and `x5u` addresses in a header are never fetched and an embedded `jwk` is never used. Nothing is uploaded and nothing is stored.</div> ## What the tool answers Four questions, in the order a resource server asks them: 1. **Is this a well-formed JWS?** Three unpadded Base64URL segments, a UTF-8 JSON header and payload, no duplicate keys, no number too large to show exactly. 2. **Does the signature verify with your key?** Only once you supply a key, only for the algorithm you expect, and never for `alg: none`. 3. **Is it current?** `exp` not passed, `nbf` reached, `iat` not in the future, each within the clock tolerance you allow. 4. **Is it meant for you?** `iss` equal to the issuer you expect and `aud` containing the audience you expect, when you enter them. The verdict joins every failure into one "Rejected:" sentence. Otherwise it states how long the token stays current and whether the signature matched. The chips repeat each check in the order above. ## Inputs ### The token The page takes a token typed, pasted anywhere on the page, dropped as a file or brought from the Unix Timestamp Converter. Before anything is read: | Step | What happens | | --- | --- | | Trim | Surrounding whitespace is removed, then a leading `Bearer ` (any case) | | Size | More than 100,000 characters is refused: "This token is too large" | | Shape | Five dot-separated parts is declined as an encrypted JWE; any count other than three gets "A JWT needs three parts: header.payload.signature" | | Paste cleanup | A pasted `Authorization: Bearer` line or a quoted token is reduced to the token, and the hint says "Token kept from what you pasted". Text that is not a token stays in the field with the decode error under it; Heal it offers a fix when it is almost a token (Remove Base64 padding, Convert to Base64URL, Remove line breaks and spaces, Keep the token only). The key is pasted into its own field | A segment must contain only letters, digits, `-` and `_`, as [RFC 4648 section 5](https://www.rfc-editor.org/rfc/rfc4648#section-5) defines the URL-safe alphabet, with no `=` padding, as [RFC 7515 section 2](https://www.rfc-editor.org/rfc/rfc7515#section-2) requires for JWS. A segment whose final character carries non-zero unused bits is refused as "noncanonical Base64URL padding bits"; it usually means a hand-edited or truncated token. ### The key or secret The key field is read only when it holds text, and only after the token decoded. What it accepts depends on the algorithm: | Algorithm family | Accepted | Refused with | | --- | --- | --- | | HS256, HS384, HS512 | The shared secret as UTF-8 text, whitespace included; with "Secret is Base64URL-encoded" ticked, unpadded Base64URL or padded standard Base64 | "The secret is not valid Base64URL" when `+` or `/` is mixed with `-` or `_`, "invalid Base64 padding" | | RS, PS, ES, Ed25519 (and `EdDSA`) | A public JWK object, or a PEM block beginning `-----BEGIN PUBLIC KEY-----` (SPKI) | "Use a public key, not a private key" for a JWK with `d`; a JWK whose `alg` differs from the selection or whose `use` is not `sig`; an Ed25519 JWK without `kty: OKP` and `crv: Ed25519`; a PKCS#1 `BEGIN RSA PUBLIC KEY` block or a certificate | A key over 100,000 characters is refused. Verification needs a secure context (HTTPS or localhost) because Web Crypto is unavailable elsewhere; the page says so instead of guessing. ### Expected algorithm, issuer, audience and tolerance "Expected algorithm" defaults to the token's own `alg`. Choosing a different one stops verification with "The token algorithm does not match the algorithm you selected" rather than trying the key anyway. The expected issuer and audience are compared exactly, character for character. Clock tolerance takes 0 to 300 seconds and applies to `exp`, `nbf` and `iat`; outside that range the field is marked invalid, the claims are evaluated with zero tolerance, and the verdict adds "clock tolerance is invalid". ## Reading the result ### Verdict and chips The verdict sentence names the outcome: "Rejected: expired 2 hours ago, signature does not match." or "Current for 59 minutes. Signature matches your key." or, with no key, "Current for 59 minutes. Signature unchecked." Each chip is one check: `exp`, `nbf`, `iat`, `iss`, `aud`, the signature and, when needed, the clock tolerance. A chip for a check you can act on is a button that focuses the field in question: the key for an unchecked or failed signature, the expected values for issuer and audience, the tolerance field when it is invalid. ### Findings Under the verdict, every check is listed worst first with its detail: the UTC time of a time claim and its relative age, "Matches your expected value", "Not checked. Enter the value your application expects." Passes fold into one line once there are two or more. ### Header and Payload The two segments are shown as tables (Enter applies an edit, Escape restores it) or as JSON you can edit freely. A time claim's value is followed by its UTC date. An edit that would change a claim's JSON type is refused ("exp must be a number of seconds since 1970"), as is a number that cannot be kept exactly. ### Token The rebuilt token is shown with its state: unchanged, re-signed, unsigned, or "signature broken". An HMAC token is re-signed with the secret in the key field; the synthetic asymmetric examples are re-signed with the private key generated in this tab; a pasted RS, PS, ES or Ed25519 token keeps its old signature, which no longer matches the edited bytes, because the page never accepts a private key. ### History Every Break it preset, every claim edit and every revert is logged with what it replaced. Revert undoes the newest change; Reset input restores the token you entered, which is also what happens when your edits bring every claim back to its original value. ### Take it further Each time claim the token carries, `exp`, `nbf` and `iat`, is offered as a link into the [Unix Timestamp Converter](https://tamperbox.dev/unix-timestamp). The value travels through same-site tab memory to a new tab; the token and the key stay on this page and nothing is put in a URL. ## Method The checks run in this order; a structural failure stops decoding, and the signature and claim checks then run independently of each other. ### Structure and encoding | Rule | Finding wording | Source | | --- | --- | --- | | Each segment is unpadded Base64URL | "Header is not valid unpadded Base64URL." | [RFC 7515 section 2](https://www.rfc-editor.org/rfc/rfc7515#section-2), [RFC 4648 section 5](https://www.rfc-editor.org/rfc/rfc4648#section-5) | | Unused bits in the last character are zero | "Header has noncanonical Base64URL padding bits." | [RFC 4648 section 3.5](https://www.rfc-editor.org/rfc/rfc4648#section-3.5) | | Header and payload are UTF-8 | "Payload contains invalid UTF-8." | [RFC 7515 section 7.1](https://www.rfc-editor.org/rfc/rfc7515#section-7.1) | | Both are JSON objects | "Payload must be a JSON object." | [RFC 7519 section 3](https://www.rfc-editor.org/rfc/rfc7519#section-3) | | No duplicate member names, at any depth | "Payload has a duplicate key: sub." | [RFC 7519 section 4](https://www.rfc-editor.org/rfc/rfc7519#section-4) | | Integers within 2^53 - 1 | "Payload has a number too large to display without losing precision." | tool rule | RFC 7519 section 4 says "The Claim Names within a JWT Claims Set MUST be unique; JWT parsers MUST either reject JWTs with duplicate Claim Names or use a JSON parser that returns only the lexically last duplicate member name". The tool rejects, because implementations that keep the first and those that keep the last disagree about what the token says, and the duplicate check sees escaped spellings of the same name. The safe-integer rule is the tool's own: JavaScript cannot show a larger integer exactly, so the page refuses rather than display a rounded claim. ### Header and algorithm | Rule | Finding wording | Source | | --- | --- | --- | | `alg` is a non-empty string | "The header must name a signing algorithm in alg." | [RFC 7515 section 4.1.1](https://www.rfc-editor.org/rfc/rfc7515#section-4.1.1) | | `alg: none` has an empty signature | "Unsigned tokens (alg: none) must have an empty signature." | [RFC 7518 section 3.6](https://www.rfc-editor.org/rfc/rfc7518#section-3.6) | | Any other algorithm has a signature | "The signature is missing." | [RFC 7515 section 5.2](https://www.rfc-editor.org/rfc/rfc7515#section-5.2) | | `crit` or `b64: false` present | verification stops: "Critical header extensions and unencoded payloads are not supported for verification." | [RFC 7515 section 4.1.11](https://www.rfc-editor.org/rfc/rfc7515#section-4.1.11), [RFC 7797](https://www.rfc-editor.org/rfc/rfc7797) | An `alg: none` token still decodes, so you can read it, but the verdict always lists "unsigned (alg: none)" among the rejection reasons and the chip reads "alg: none · unsigned". [RFC 8725 section 2.1](https://www.rfc-editor.org/rfc/rfc8725#section-2.1) describes why: a verifier that accepts `none` because the token asked for it has no verifier at all. `jku`, `x5u` and `jwk` are shown as plain header members and never acted on, so a token cannot choose its own key, the attack that [RFC 8725 section 2.1](https://www.rfc-editor.org/rfc/rfc8725#section-2.1) and [section 3.10](https://www.rfc-editor.org/rfc/rfc8725#section-3.10) warn about. ### Signature verification Verification runs only with a key in the field and only for the expected algorithm, which must equal the token's `alg`. [RFC 8725 section 3.1](https://www.rfc-editor.org/rfc/rfc8725#section-3.1) is the rule: "Libraries MUST enable the caller to specify a supported set of algorithms and MUST NOT use any other algorithms when performing cryptographic operations". The algorithm also decides which key shapes are accepted, which is the key-algorithm binding of [RFC 8725 section 3.2](https://www.rfc-editor.org/rfc/rfc8725#section-3.2): an HMAC secret is never tried against an RSA token and a public key is never used as an HMAC secret. | Identifier | Web Crypto operation | Notes | | --- | --- | --- | | HS256, HS384, HS512 | HMAC with SHA-256, SHA-384, SHA-512 | [RFC 7518 section 3.2](https://www.rfc-editor.org/rfc/rfc7518#section-3.2); a secret shorter than the hash output verifies but is flagged | | RS256, RS384, RS512 | RSASSA-PKCS1-v1_5 | [RFC 7518 section 3.3](https://www.rfc-editor.org/rfc/rfc7518#section-3.3) | | PS256, PS384, PS512 | RSA-PSS with salt lengths 32, 48 and 64 bytes | [RFC 7518 section 3.5](https://www.rfc-editor.org/rfc/rfc7518#section-3.5): the salt length equals the hash output | | ES256, ES384, ES512 | ECDSA on P-256, P-384, P-521 | [RFC 7518 section 3.4](https://www.rfc-editor.org/rfc/rfc7518#section-3.4) | | Ed25519, `EdDSA` | Ed25519 | [RFC 8037 section 3.1](https://www.rfc-editor.org/rfc/rfc8037#section-3.1); `EdDSA` accepted for the Ed25519 curve only | The signed input is the ASCII of the first two segments joined by a dot, as [RFC 7515 section 5.2](https://www.rfc-editor.org/rfc/rfc7515#section-5.2) step 8 requires. The result is "Signature matches this key" or "Signature does not match this key". A mismatch means the wrong key, a key rotated out of the issuer's set (compare `kid`), the wrong secret encoding, or a token changed after signing. A match proves only that this key verifies these bytes; it says nothing about whether this key should be trusted. ### Time claims `exp`, `nbf` and `iat` must be NumericDates, "a JSON numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time" ([RFC 7519 section 2](https://www.rfc-editor.org/rfc/rfc7519#section-2)). A quoted value, or a number a JavaScript date cannot hold, fails with "Expected a NumericDate". With tolerance `t` seconds and the device clock `now`: | Claim | Fails when | Chip | | --- | --- | --- | | `exp` | `now` is at or past `exp + t` | "exp · expired 2 hours ago"; inside the tolerance: "exp · within tolerance" | | `nbf` | `nbf` is later than `now + t` | "nbf · starts in 59 minutes" | | `iat` | later than `now + t`, as a notice only | "iat · in the future" | | `exp` absent | never; a notice | "exp · never expires" | RFC 7519 [section 4.1.4](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4): "the current date/time MUST be before the expiration date/time listed in the exp claim"; [section 4.1.5](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.5): "the current date/time MUST be after or equal to the not-before date/time". Both allow "some small leeway, usually no more than a few minutes, to account for clock skew", which is the 300-second ceiling. Whether `exp` is required is the application's decision, so its absence is a notice. Times come from your device clock and the verdict re-evaluates every ten seconds while the tab is visible. `auth_time` is shown as a date but not checked. ### Issuer and audience `iss` must be a string; `aud` a string or an array of strings ([RFC 7519 section 4.1.1](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.1) and [section 4.1.3](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3)). Another type fails as "wrong type". With an expected value entered, `iss` must equal it and the expected audience must equal `aud` or be one of its members: "If the principal processing the claim does not identify itself with a value in the aud claim when this claim is present, then the JWT MUST be rejected." The comparison is exact, so a trailing slash or a different case is a mismatch, which is what [RFC 7519 section 2](https://www.rfc-editor.org/rfc/rfc7519#section-2) prescribes for StringOrURI values. An empty expectation reports "not checked", never a pass; [RFC 8725 section 3.8](https://www.rfc-editor.org/rfc/rfc8725#section-3.8) is why the audience check matters: a token for one service replayed against another passes every other check. ### Rebuilding edited tokens An edited header or payload is re-encoded and the token rebuilt. With a usable signing key the state is "signed"; otherwise the old signature is kept and the state is "stale", because the bytes it covered have changed. Break signature replaces the first character of the signature with `A` (or `B` when it already is `A`), which keeps the segment canonical and guarantees a mismatch. A rebuilt `alg: none` token has an empty signature. ## Standards and conformance ### RFC 7519: JSON Web Token Implemented: section 2 (NumericDate, exact StringOrURI comparison), section 3 (the Claims Set is a JSON object), section 4 (unique claim names), sections 4.1.1 to 4.1.6 (`iss`, `sub` shown only, `aud`, `exp`, `nbf`, `iat`), section 7.2 steps 1 to 10 for a JWS. Not implemented: step 7 for nested JWTs (`cty: JWT` is shown, not unwrapped), section 5.3 replicating claims as header parameters, and any JWE path. Stricter than the text: duplicates are rejected, not resolved. The tool does not apply [RFC 7519 section 4.1.7](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.7) `jti` replay detection; it has no store to check against. ### RFC 7515 and RFC 7518: JWS and JWA Implemented: compact serialisation (section 3.1 of RFC 7515), Base64URL without padding (section 2), the signing input of section 5.2, the `alg` parameter (section 4.1.1), refusal of `crit` (section 4.1.11) and of `b64: false` from [RFC 7797 section 3](https://www.rfc-editor.org/rfc/rfc7797#section-3). From RFC 7518 the algorithms in the table above and `none` (section 3.6). Not implemented: `jku`, `x5u`, `x5c` and `x5t` resolution (section 4.1.2 to 4.1.8), JSON serialisation, RS and PS keys supplied as PKCS#1, and ECDSA curves beyond the three named. Where it differs: [RFC 7518 section 3.2](https://www.rfc-editor.org/rfc/rfc7518#section-3.2) says an HMAC key "MUST be" at least the hash size; the tool verifies a shorter secret and flags it, so a test token still reads while the weakness is named. ### RFC 7517 and RFC 8037: keys A JWK is accepted when it is a public key ([RFC 7517 section 4](https://www.rfc-editor.org/rfc/rfc7517#section-4) members; a private `d` from [RFC 7518 section 6](https://www.rfc-editor.org/rfc/rfc7518#section-6) is refused), its `use` is absent or `sig` ([section 4.2](https://www.rfc-editor.org/rfc/rfc7517#section-4.2)) and its `alg` is absent or equal to the selection ([section 4.4](https://www.rfc-editor.org/rfc/rfc7517#section-4.4)). Ed25519 keys follow [RFC 8037 section 2](https://www.rfc-editor.org/rfc/rfc8037#section-2) (`kty: OKP`, `crv: Ed25519`); the JOSE identifier `EdDSA` from [section 3.1](https://www.rfc-editor.org/rfc/rfc8037#section-3.1) is accepted and mapped to the browser's Ed25519 operation. Ed448 is not supported. JWK Sets (`keys` arrays) are not read; paste the one key, chosen by `kid`. ### RFC 8725: best current practices Followed: 2.1 and 3.1 (no `none` verification, caller-chosen algorithms), 3.2 (key and algorithm bound), 3.8 (audience checked when supplied), 3.10 (no key fetched from the token). Partly followed: 3.9 (the typ header is shown, not enforced) and 3.11 (exact issuer match when supplied). Not applicable: 3.5 to 3.7 (key management in the application). ### What the tool does not check Revocation, replay (`jti`), nested tokens, encryption ([RFC 7516](https://www.rfc-editor.org/rfc/rfc7516) tokens are declined on sight), certificate chains behind `x5c`, and the application's own rules about scopes, subjects and roles. ## Finding reference ### Structure | Finding | Severity | Section | Meaning for the receiver | Fix | | --- | --- | --- | --- | --- | | A JWT needs three parts | fail | RFC 7515 §3.1 | Not a JWS; nothing can be read | Copy the whole token; check for a cut at a line break | | Encrypted token (JWE) | fail | RFC 7516 | Claims are encrypted; this tool cannot read them | Decrypt with the recipient's key elsewhere | | Not valid unpadded Base64URL | fail | RFC 7515 §2 | Standard Base64 or padding was used | Re-encode with the URL-safe alphabet, no `=` | | Noncanonical padding bits | fail | RFC 4648 §3.5 | The segment was edited or truncated by hand | Regenerate the token | | Invalid UTF-8, not valid JSON, must be a JSON object | fail | RFC 7519 §3 | The segment does not hold a claims object | Fix the producer's serialisation | | Duplicate key | fail | RFC 7519 §4 | Libraries disagree about which value wins | Emit each claim once | | Number too large | fail | tool rule | The value cannot be shown exactly | Carry large identifiers as strings | ### Header, algorithm and signature | Finding | Severity | Section | Meaning for the receiver | Fix | | --- | --- | --- | --- | --- | | alg: none · unsigned | fail | RFC 8725 §2.1 | Anyone can change the claims; the token proves nothing | Sign with a real algorithm; reject `none` at the verifier | | The signature is missing | fail | RFC 7515 §5.2 | A signed algorithm with nothing to verify | Regenerate the token | | signature · add a key | notice | RFC 7515 §5.2 | Nothing verified yet | Enter the secret or public key | | signature · does not match | fail | RFC 7515 §5.2 | Wrong key, wrong encoding or altered token | Compare `kid` with the issuer's current keys; check the secret's encoding | | signature · broken by your edits | fail | RFC 7515 §5.2 | The old signature no longer covers the bytes | Re-sign with the secret, or use as a negative test | | signature · broken on purpose | fail | RFC 7515 §5.2 | A deliberate bad-signature fixture | None; every server should reject it | | signature · could not check | fail | RFC 7518 §3 | Algorithm mismatch, key refused, `crit`, `b64: false` or no secure context | Read the detail: it names the cause | | Weak HMAC secret | notice | RFC 7518 §3.2 | Fine for tests, not for production | Use a secret at least as long as the hash output | ### Time, issuer and audience | Finding | Severity | Section | Meaning for the receiver | Fix | | --- | --- | --- | --- | --- | | exp · expired | fail | RFC 7519 §4.1.4 | A conforming server rejects it | Issue a new token; check the issuer's clock and lifetime | | exp · within tolerance | pass | RFC 7519 §4.1.4 | Accepted only thanks to your leeway | Treat as expiring; renew | | exp · never expires | notice | RFC 7519 §4.1.4 | Valid until the key is rotated | Add `exp` unless the application forbids it | | nbf · starts in | fail | RFC 7519 §4.1.5 | Not yet usable | Wait, or fix the issuer's clock | | iat · in the future | notice | RFC 7519 §4.1.6 | The issuer's clock is ahead | Synchronise clocks | | not a valid time | fail | RFC 7519 §2 | A string or out-of-range number where seconds were expected | Emit a JSON number of seconds | | iss or aud · does not match | fail | RFC 7519 §4.1.1, §4.1.3 | Issued by, or for, someone else | Check the expected value for trailing slashes and case; reject the token otherwise | | iss or aud · wrong type | fail | RFC 7519 §4.1.1, §4.1.3 | The claim is not a string (or array of strings) | Fix the issuer | | iss or aud · not checked | notice | RFC 8725 §3.8 | You have not said who you are | Enter the expected value | | clock tolerance · invalid | fail | RFC 7519 §4.1.4 | Settings error; claims judged with zero tolerance | Enter 0 to 300 | ## Guide ### The token is expired, or not valid yet 1. Read the `exp` or `nbf` chip: it names the UTC time and the distance from now. 2. Compare with the issuer's clock. A few seconds off is clock skew; set a tolerance of up to 300 seconds and see whether the chip turns to "within tolerance". More than that is a lifetime or a clock problem at the issuer. 3. Obtain a fresh token and paste it. The verdict should read "Current for" the remaining lifetime. ### exp decodes to a year far in the future The claim was written in milliseconds. The table shows the date tens of thousands of years ahead and the chip says the token never meaningfully expires. Divide by 1000 at the issuer, or send the value to the Unix Timestamp Converter from Take it further and read it as milliseconds to confirm. ### Wrong audience or issuer Enter the exact values your application compares against. A mismatch chip opens the expected-values panel and focuses the field. If the token's `aud` is an array, your value must be one of its members; a trailing slash on either side is a mismatch, not a near miss. ### alg: none The token decodes, the chip reads "alg: none · unsigned", and the verdict rejects it. No key makes it pass. If a token from a real issuer arrives this way, the issuer is misconfigured; if your server accepted it, the verifier must be configured with an explicit algorithm allow-list. ### The signature does not match | Check | How | | --- | --- | | Algorithm | Expected algorithm equals the header's `alg`; a different selection stops with a mismatch message | | Key | `kid` in the header against the issuer's current key set; a rotated key is the usual cause | | Secret encoding | A Base64-exported secret needs "Secret is Base64URL-encoded"; a text secret must keep its exact whitespace | | Token integrity | Any edit after signing changes the bytes; Reset input and verify the original | ### A key is refused The detail names the cause: a private JWK (`d` present), a JWK with `use` other than `sig` or a conflicting `alg`, a PKCS#1 block instead of SPKI, a certificate, or no secure context. Export the public key as SPKI (`openssl pkey -in private.pem -pubout`) or as a public JWK. ### Break it cases | Button | What it loads | What it shows | | --- | --- | --- | | Expire it | `exp` one hour ago | "Rejected: expired 1 hour ago" | | Not yet valid | `nbf` one hour ahead, `exp` moved to two hours ahead if it was sooner | "not valid for another 1 hour" | | Wrong audience | `aud` set to `someone-else` | "audience does not match" once an expected audience is entered | | alg: none | header `alg` set to `none` | "unsigned (alg: none)" | | Break signature | the first signature character swapped | "signature altered" | Every preset rebuilds the token: the HMAC example is re-signed with its secret, so the only failing check is the one the preset introduced. Revert in History undoes one preset; Reset input undoes them all. ### An independent check Verify an HS256 token outside Tamperbox with OpenSSL. With the token in `$T` and the secret in `$S`: ```sh data=$(printf %s "$T" | cut -d. -f1-2) printf %s "$data" | openssl dgst -sha256 -hmac "$S" -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=' printf %s "$T" | cut -d. -f3 ``` The two printed lines are equal when the signature verifies. For an RS256 token, decode the signature segment to a file and run `openssl dgst -sha256 -verify public.pem -signature sig.bin` over the same first two segments. ## Worked example The page opens on a synthetic HS256 token created in your tab when the page loads: header `alg: HS256`, `typ: JWT`; payload `sub: qa-example`, `name: Demo user`, `iss: https://issuer.example`, `aud: tamperbox-demo`, `role: tester`, `iat` now and `exp` one hour ahead. It is signed with a demo secret the page shows you, and the secret is already in the key field, so the opening verdict reads "Current for 59 minutes. Signature matches your key." with every chip green except `iss` and `aud`, which read "not checked" until you enter `https://issuer.example` and `tamperbox-demo`. The token is reserved sample data with a reserved issuer name; it is not a credential for anything and a new one is signed on every load, so its exact bytes are never the same twice. Choosing an asymmetric example generates a key pair in the tab, shows the public key as PEM, and keeps the private key non-extractable, which is why those examples can be re-signed while a pasted RS256 token cannot. ## For agents The Tamperbox MCP server exposes two MCP tools: use `search` to inspect the catalog and schema, then use `execute` to call the selected operation through `tamperbox.request`. The JWT page maps to four `POST /v1/tools/...` operations: | Operation | Required input | Result | | --- | --- | --- | | `jwt_decode` | An `application/jwt` text artifact | A JSON artifact containing the decoded header and payload; no verification | | `jwt_verify` | `token`, `key` and an explicit `algorithm` | Separate signature evidence, claim checks, header and payload | | `jwt_rebuild` | JSON `header` and `payload`; optionally an HMAC secret or old signature | A token whose state is `unsigned`, `signed`, `stale` or `broken` | | `jwt_fixture` | Optional `algorithm`, `header` and `payload` | A synthetic token, selected algorithm and verification key; private keys are not retained | All responses also carry warnings and provenance. Keep these with any conclusion: - A decoded token is readable, not trusted; a verified signature proves only that the supplied key verifies those bytes. - Fixtures are not application credentials, and a rebuilt token passes for anyone who trusts the same key. - None of the operations establishes application authorisation: scopes, roles and `jti` replay are the application's rules. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where a token travels when an agent, rather than the browser page, decodes it. ## Limits - Decoding proves readability, not origin; verification proves that one key verifies these bytes, not that the key is the right one to trust. - No key is fetched from `jku`, `x5u` or an embedded `jwk`, and no key set is read; choose the key by `kid` yourself. - JWE, nested JWTs, `crit` extensions and `b64: false` payloads are declined or left unverified. - Private asymmetric keys are never accepted, so only HMAC tokens and the tab's own examples can be re-signed. - Times come from your device clock; a wrong local clock produces wrong expiry findings. - Exact string comparison for issuer and audience; no normalisation of case or trailing slashes. - Input is limited to 100,000 characters for the token and the key. - Nothing is stored, and the token is not put in a URL; the Take it further link carries only the selected claim value. ## References - [RFC 7519, JSON Web Token (JWT)](https://www.rfc-editor.org/rfc/rfc7519). Proposed Standard, May 2015; updated by RFC 7797 and RFC 8725. Sections used: [2](https://www.rfc-editor.org/rfc/rfc7519#section-2), [3](https://www.rfc-editor.org/rfc/rfc7519#section-3), [4](https://www.rfc-editor.org/rfc/rfc7519#section-4), [4.1.1](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.1), [4.1.3](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3), [4.1.4](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4), [4.1.5](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.5), [4.1.6](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6), [4.1.7](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.7) (not applied) and [7.2](https://www.rfc-editor.org/rfc/rfc7519#section-7.2). - [RFC 7515, JSON Web Signature (JWS)](https://www.rfc-editor.org/rfc/rfc7515). Proposed Standard, May 2015. Sections used: [2](https://www.rfc-editor.org/rfc/rfc7515#section-2), [3.1](https://www.rfc-editor.org/rfc/rfc7515#section-3.1), [4.1.1](https://www.rfc-editor.org/rfc/rfc7515#section-4.1.1), [4.1.11](https://www.rfc-editor.org/rfc/rfc7515#section-4.1.11), [5.2](https://www.rfc-editor.org/rfc/rfc7515#section-5.2) and [7.1](https://www.rfc-editor.org/rfc/rfc7515#section-7.1). - [RFC 7518, JSON Web Algorithms (JWA)](https://www.rfc-editor.org/rfc/rfc7518). Proposed Standard, May 2015; updated by [RFC 9864](https://www.rfc-editor.org/rfc/rfc9864). Sections used: [3.2](https://www.rfc-editor.org/rfc/rfc7518#section-3.2), [3.3](https://www.rfc-editor.org/rfc/rfc7518#section-3.3), [3.4](https://www.rfc-editor.org/rfc/rfc7518#section-3.4), [3.5](https://www.rfc-editor.org/rfc/rfc7518#section-3.5), [3.6](https://www.rfc-editor.org/rfc/rfc7518#section-3.6) and [6](https://www.rfc-editor.org/rfc/rfc7518#section-6). - [RFC 7517, JSON Web Key (JWK)](https://www.rfc-editor.org/rfc/rfc7517). Proposed Standard. Sections used: [4](https://www.rfc-editor.org/rfc/rfc7517#section-4), [4.2](https://www.rfc-editor.org/rfc/rfc7517#section-4.2) and [4.4](https://www.rfc-editor.org/rfc/rfc7517#section-4.4). - [RFC 8037, CFRG Elliptic Curve Diffie-Hellman (ECDH) and Signatures in JOSE](https://www.rfc-editor.org/rfc/rfc8037). Proposed Standard, January 2017. Sections used: [2](https://www.rfc-editor.org/rfc/rfc8037#section-2) and [3.1](https://www.rfc-editor.org/rfc/rfc8037#section-3.1). - [RFC 8725, JSON Web Token Best Current Practices](https://www.rfc-editor.org/rfc/rfc8725). Best Current Practice, February 2020; updates RFC 7519. Sections used: [2.1](https://www.rfc-editor.org/rfc/rfc8725#section-2.1), [3.1](https://www.rfc-editor.org/rfc/rfc8725#section-3.1), [3.2](https://www.rfc-editor.org/rfc/rfc8725#section-3.2), [3.8](https://www.rfc-editor.org/rfc/rfc8725#section-3.8) and [3.10](https://www.rfc-editor.org/rfc/rfc8725#section-3.10). - [RFC 7797, JSON Web Signature (JWS) Unencoded Payload Option](https://www.rfc-editor.org/rfc/rfc7797). Proposed Standard; updates RFC 7519. Section used: [3](https://www.rfc-editor.org/rfc/rfc7797#section-3) (declined for verification). - [RFC 7516, JSON Web Encryption (JWE)](https://www.rfc-editor.org/rfc/rfc7516). Proposed Standard. Five-part tokens are declined; no section is applied. - [RFC 4648, The Base16, Base32, and Base64 Data Encodings](https://www.rfc-editor.org/rfc/rfc4648). Proposed Standard. Sections used: [3.5](https://www.rfc-editor.org/rfc/rfc4648#section-3.5) and [5](https://www.rfc-editor.org/rfc/rfc4648#section-5). --- # Limits Execution, request, result, and concurrency limits for Tamperbox MCP code mode. Canonical: https://docs.tamperbox.dev/reference/limits/ Updated: 2026-10-20 Applies to: MCP 0.3.0 Outputs: Constraints for planning a bounded MCP execution Limitations: Hosted infrastructure can add limits outside the package defaults. ## Default budgets | Resource | Default | | --- | --- | | Code | 64 KiB UTF-8 | | Input to each API call | 1 MiB UTF-8 | | Result from each API response | 2 MiB serialized JSON | | JSON nesting | 40 levels | | Execution time | 15 seconds, selectable from 1-30 seconds | | Upstream request time | 30 seconds, bounded by the execution deadline | | API calls per execution | 20 | | Parallel API calls | 4 | | Active executions per process | 4 | | QuickJS allocator budget | 32 MiB | | WebAssembly linear memory | 64 MiB | ## Counting API calls `apiCalls` counts bridge calls attempted, including host-validation failures. Guest serialization failures happen before dispatch and do not consume the call budget. ## Execution completion Await every API request. Calls still running when the submitted function completes are cancelled. Responses do not retry or follow redirects unless the documented operation itself defines that behavior. The hosted API applies an approximate 60-request-per-minute caller budget; network probes have a separate, lower budget. Hosted MCP users can share the server's upstream caller identity. Twenty permitted bridge calls are therefore not a promise that twenty network checks will be accepted. Start with small batches, stop on rate denial and respect `details.retryAfterSeconds` when supplied. MCP exposes a bounded upstream error code and retry delay, not raw upstream error bodies, and does not automatically retry submitted work. ## Result serialization Return JSON-compatible values. BigInt values, cyclic objects, functions, symbols, and non-finite numbers are rejected. `undefined` becomes `null` at the top level and is omitted from object properties under normal JSON rules. --- # llms.txt Checker & Generator How the llms.txt checker fetches and reads a site's llms.txt, the outline an agent builds from it, every rule it applies, how it compares the file with the sitemap and drafts a new one, and how to fix each finding. Canonical: https://docs.tamperbox.dev/tools/llms-txt/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public host name, or an llms.txt file to paste Outputs: A verdict, findings, the outline an agent reads, the file line by line, a draft built from the site and repairs Limitations: llms.txt is a proposal some AI tools read and many do not; links are checked for form, not requested; the draft names pages from the site's own links and paths The tool page is [tamperbox.dev/llms-txt](https://tamperbox.dev/llms-txt). It checks `tamperbox.dev` live when opened, says whether its llms.txt follows the format and what an agent would read from it, and drafts a file from the site. This page is the long version: what is fetched, every rule, how the outline and the draft are made, and how to fix each finding. <div class="tb-callout"><strong>Where processing happens:</strong> a pasted llms.txt is read in your browser and never uploaded. A host name is sent to the Tamperbox server, which fetches <code>/llms.txt</code>, the home page, <code>/robots.txt</code> and up to two top-level sitemaps, each with up to four index children, without cookies; the file is read and the draft written in your browser. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. Sample hosts on the reserved <code>.example</code> zone are answered in the browser from a fixture.</div> ## What the tool answers 1. **Does the site publish an llms.txt an agent can use?** Served as text at `/llms.txt`, not as a web page. 2. **What does an agent read from it?** The name, the summary, the notes and each section's links, as an outline. 3. **Does it follow the format?** Every line an agent would misread: a missing name, relative links, links outside lists, empty sections. 4. **What does it leave out?** Sitemap pages the file never links. 5. **What could it say?** A draft from the site's own name, description, navigation and sitemap. ## Inputs ### A host `example.com` or a full address; the host is kept. The check runs when you stop typing, or on Enter. The usual refusals apply: spaces, other schemes, credentials, non-standard ports, IP addresses and single labels. ### A pasted file Text with a newline, or starting with `#`, `>`, a list link `- [` or a link `[Name](`, is read as llms.txt, in the browser. Nothing is fetched, so there is no draft and no sitemap comparison, and relative links cannot be resolved unless the current programmatic load retains a base from the preceding host lookup; direct typing or pasting into the field clears that base. Files up to 2 MiB (`.txt`, `.md`) can be dropped or opened. A pasted address loses quotes, brackets and trailing punctuation and keeps the host; text that fits nothing stays as pasted. ## Reading the result ### Verdict and chips "llms.txt with n links in m sections, in the expected format." or "… and n things to fix.", "No llms.txt at host." with the draft offered, "llms.txt is a web page." or "Empty llms.txt." The chips count problems and scroll to the findings. Two items say where the input went. ### Findings Worst first, line findings prefixed with their line; two or more passing findings are grouped under an expandable **checks passed** row. A single passing finding stays visible. ### What an agent reads The outline: the name (or "No name" in red), the summary (or the first note shown in its place), then each section with its link count and links. A section titled Optional is marked as one an agent may skip. Relative links are tinted. ### llms.txt The file as written, numbered, issue lines tinted and noted. Long files show their first 60 lines and every marked line; **Show all n lines** lists the rest, and **Show the first 60 lines** folds it again. Folding is offered only when at least ten unmarked lines after line 60 can be hidden; marked lines remain visible. ### Draft from the site A complete llms.txt built from the site, with a note saying how many link names came from the site's own links and how many from URL paths. **Copy**, **Download llms.txt**, and **Check the draft**, which loads the draft into the box and checks it. ### History History follows the current result evidence. Break it and Heal it record input changes, newest first. **Revert** restores the input before the latest recorded change; **Reset input** restores the input before the first retained change and clears the list. **Restore input before this break** under Heal it also reverts the latest change. These actions reload and check the restored input. Restoring a public address can therefore send a new request, including on the two tools whose ordinary typing waits for a run button. Editing or pasting a new input clears History. The list lives in the current page; it is not saved monitoring data and does not restore an old network response. **Check the draft** is also logged as an input change, so Revert returns to the input that produced the draft. ### Take it further Only links with an available result value appear. | Follow-up | Value carried | When offered | | --- | --- | --- | | [Redirect Checker](https://tamperbox.dev/redirect-checker) | `https://host/llms.txt` | A host was checked | | [Website Down Checker](https://tamperbox.dev/website-down-checker) | First absolute HTTP(S) link | Such a link appears in the file | | [SSL Checker](https://tamperbox.dev/ssl-checker) | A linked host outside the checked site | The file names a different host outside the site's subdomains | ### Related checks and input transfer Check the rest carries the current address to a sibling tool. Take it further carries the specific value listed above. Pasted file contents are not transferred through these links. Transfers temporarily use browser `sessionStorage` with a one-use random token in the URL fragment; the input itself is not in the URL. The destination accepts a transfer for less than one minute and removes the token. Manual destination tools wait for their run button or Enter. Each destination collects new evidence. A follow-up link does not confirm the original verdict or repair the remote site. ### Result cards Six expandable cards below the result explain its meaning, give a beginner explanation, offer an agent prompt, describe good practice, suggest fixes and state limitations. Their text follows the current result; it is not another measurement. Open a card for its full explanation and the relevant [Method](#method) or [Guide](#guide). The agent prompt can be copied for review; copying it does not run a repair or send it to an agent. ## Method ### Fetching For a host, three fetches start together on `https://host`: `/llms.txt` (up to 5 redirects, first 2 MiB), the home page (up to 10 redirects, first 512 KiB of HTML) and `/robots.txt`. Then up to two sitemaps are read: those robots.txt lists, or `/sitemap.xml`, plus up to four children of each top-level sitemap index. The home page and sitemaps feed the draft and the coverage check; if they fail, the file is still checked. | Response for /llms.txt | Severity | | --- | --- | | 400 or above | INFO, "No llms.txt": nothing breaks; a draft is offered | | HTML content type or body | FAIL: an agent reads a web page | | Empty | CHECK | ### Structure The [llms.txt proposal](https://llmstxt.org/#format) defines the file as Markdown with "an H1 with the name of the project or site. This is the only required section", then optionally a blockquote summary, other details, and "Zero or more markdown sections delimited by H2 headers, containing “file lists” of URLs". Each list item is "a required markdown hyperlink `[name](url)`, then optionally a : and notes about the file". Headings and lists follow [CommonMark](https://spec.commonmark.org/0.31.2/). The tool reads the file line by line, skipping fenced code blocks: | Rule | Severity | Repair | | --- | --- | --- | | No `#` line at all | FAIL | Add "# Name" first (when a host was checked) | | Text before the `#` line | FAIL | | | A second `#` line | CHECK | Turn extra H1s into sections | | No `>` summary under the name | INFO | | | A name but no `##` sections | CHECK | | | A `##` section with no links | CHECK | | | `###` or deeper heading | INFO: read as a note | | | A link without a scheme | CHECK | Make links absolute (when a host was checked) | | A `[Name](url)` that is not a list item | CHECK | Put links in a list | | A list item with no link | CHECK | | | The same URL twice | INFO | | Lines inside sections are links when they match `- [Name](url)` with an optional quoted title and `: notes`; `*` and `+` bullets are accepted. Blockquote lines before the first section join into the summary; other text before it is kept as notes. A section titled `Optional`, which the proposal uses "by convention, for secondary information: links an agent can skip when a shorter context is needed", is marked so in the outline. ### Coverage When both the file and a sitemap were read, every sitemap URL other than the home page is compared with the file's links, after resolving relative links. Missing pages are INFO with the count and two example paths: a prompt to link what an agent needs most, not a target to list everything. ### The draft Only what the site publishes: - the name from `og:site_name`, else the `<title>` cut at the first " | ", " · ", " – ", " — " or " - "; - the summary from `og:description`, else the meta description; - same-origin links with text inside the home page's `nav`, `header` and `footer`, named with that text; - same-origin sitemap URLs not already in the navigation, named from the last part of their path. Privacy, terms, cookies, legal, imprint, impressum and disclaimer pages go into Optional; other pages one level deep go under Pages, deeper ones grouped by their first path segment, at most 40 links per section. Navigation added by scripts is not seen. ## Standards and conformance ### The llms.txt proposal (llmstxt.org) Implemented: the H1 name as the only required part, the blockquote summary, notes, H2 sections of link lists with optional notes, the Optional section. Stricter than the text: a relative link is a CHECK, because the proposal's examples use full URLs and agents fetch the file on its own. Not implemented: the companion `.md` versions of pages and `llms-full.txt`, which the proposal suggests but does not require. The proposal is a community document, not an RFC or W3C specification; [llmstxt.org](https://llmstxt.org/) is its canonical text. ### CommonMark Headings, block quotes, list items and inline links are recognised by their CommonMark forms; fenced code blocks are skipped. The parser is line-based, so multi-line list items and reference-style links are not read as links. ### Sitemaps protocol and RFC 9309 Sitemaps are found through robots.txt Sitemap lines ([RFC 9309, section 2.2.4](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.4)) or at `/sitemap.xml`, and read as the [Sitemaps protocol](https://www.sitemaps.org/protocol.html) defines; the [robots.txt checker](https://docs.tamperbox.dev/tools/robots-txt-checker/) checks a bounded set of their syntax and entries. ## Finding reference | Finding | Severity | What it means for an agent | Fix | | --- | --- | --- | --- | | No llms.txt (n) | INFO | Nothing to read; nothing breaks | Optional; the draft is a start | | llms.txt is a web page | FAIL | Reads HTML | Serve Markdown text | | Empty llms.txt | CHECK | Nothing to read | Write the file | | Line 1: No H1 name | FAIL | Cannot tell what the file describes | Add "# Name" (Heal it) | | Line n: H1 is not the first line | FAIL | May miss the name | Move it first | | Line n: A second H1 | CHECK | Extra name ignored | Use ## (Heal it) | | Line n: No summary | INFO | No one-line context | Add "> summary" | | Line n: No ## sections | CHECK | Nothing to follow | Add sections | | Line n: Section "x" has no links | CHECK | Adds nothing | Add links or remove | | Line n: Hn heading | INFO | Read as a note | Use ## | | Line n: Relative link | CHECK | Leads nowhere out of context | Full URLs (Heal it) | | Line n: Link outside a list | CHECK | Read as a note | List item (Heal it) | | Line n: List item without a link | CHECK | Skipped | Add the link | | Line n: Linked twice | INFO | | Keep one | | n sitemap pages not linked | INFO | Pages not pointed to | Link the important ones | ## Guide ### No llms.txt Decide whether you want one. If yes: review the draft, rename links that came from paths, add a note to each that needs it, cut what an agent does not need, and publish it at `/llms.txt` as `text/plain` or `text/markdown`. Confirm outside Tamperbox: `curl -s https://example.com/llms.txt | head`. ### The file is served as HTML Exempt `/llms.txt` from the catch-all route, so the file is served before the app. ### Format problems Use Heal it for the name, extra H1s, relative links and links outside lists; each rewrites the whole file for review. For list items without links and empty sections, add the links by hand. Then check again. ### Choosing what to link Link the pages an agent is asked about: getting started, pricing, the API reference, support. Put the rest under `## Optional`. The coverage finding lists sitemap pages you left out; it is not a target. ### Break it cases | Case | What it loads | What to look at | | --- | --- | --- | | No H1 name | Your file without its `#` line | No H1 name; Heal it adds it back | | Relative links | Your file with every link made relative | Relative link; Heal it makes them absolute | | Links without a list | Your file with the list bullets removed | Link outside a list; Heal it lists them | | No llms.txt | A sample host without the file | The draft | | Served as a web page | A sample single-page app | llms.txt is a web page | The first three are built from your own file when you entered a host or pasted one. ## Worked example The page opens with a live check of `tamperbox.dev`. It fetches llms.txt and supporting site material to build the outline and, when the home page is available, a draft. Link counts, findings and suggested sections depend on the current site. Read the outline first: the name, summary, notes and H2 link lists should describe what a reader can learn. A file can be syntactically readable yet omit the task-specific pages an agent needs. Compare the draft's navigation-derived names with names inferred from URL paths; rename ambiguous entries before using them. Use **Check the draft** to load the generated text into the parser. This is a local input replacement, not publication. Review every destination and remove irrelevant links before saving the file at the site's root. A missing or blocked supporting sitemap can reduce coverage without making the existing llms.txt invalid. The checker does not request the linked pages, so verify important destinations independently before presenting the file as ready to publish. ## For agents Use the Tamperbox MCP `search` tool to inspect the schema, then `execute` with `tamperbox.request` to call `POST /v1/tools/llms_txt`. Supply the required `domain` field as a public domain name. The operation is named `llms_txt`; the browser page’s hyphenated identifier is not the API operation name. The operation fetches llms.txt and returns `evidence` and a parsed `report`. It does not fetch the home page and sitemap collection to generate the browser’s draft or coverage comparison. Links are parsed, not requested. Keep the input, observation time, source limitations and inconclusive results with any summary. Browser fixtures are demonstrations, not live MCP targets. Do not turn missing evidence into a passing check or infer that an inaccessible resource has been deleted. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/), [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) and [Security and privacy](https://docs.tamperbox.dev/reference/security/). ## Limits - One fetch each of llms.txt (2 MiB), the home page (512 KiB) and robots.txt, and up to two top-level sitemaps with up to four children each. - Links are not requested. - The parser is line-based CommonMark; multi-line list items and reference links are not read as links. - Live checks are rate limited. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. ## References - [The llms.txt proposal](https://llmstxt.org/), [format](https://llmstxt.org/#format). - [CommonMark specification 0.31.2](https://spec.commonmark.org/0.31.2/): [ATX headings](https://spec.commonmark.org/0.31.2/#atx-headings), [block quotes](https://spec.commonmark.org/0.31.2/#block-quotes), [list items](https://spec.commonmark.org/0.31.2/#list-items), [links](https://spec.commonmark.org/0.31.2/#links). - [Sitemaps XML format, protocol 0.9](https://www.sitemaps.org/protocol.html). - [RFC 9309, Robots Exclusion Protocol](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.4), section 2.2.4. --- # Minecraft Server Status Checker How the Minecraft Server Status Checker follows the SRV record, asks a Java Edition server for its server list status and ping, what every verdict and finding means, and how to fix servers players cannot join. Canonical: https://docs.tamperbox.dev/tools/minecraft-server-status/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A Java Edition server address (host name or public IP), with or without a port; the name must resolve only to public addresses Outputs: The server list entry the game would draw (message, players, version, signal bars), the SRV target and address connected to, connect and ping times, and findings for full, offline, old or misconfigured servers Limitations: Java Edition only (Bedrock uses UDP); one region; version, players and message are self-reported; the check never logs in or joins The tool page is [tamperbox.dev/minecraft-server-status](https://tamperbox.dev/minecraft-server-status). It opens on `play.harbor-supply.example`, a local sample survival server with fixed answers, and checks your own server when you press Check server. This page is the long version: how the address is resolved the way the game resolves it, what the status exchange asks, what each verdict and finding means for players, and how to confirm a fix without Tamperbox. <div class="tb-callout"><strong>Where processing happens:</strong> typing sends nothing. Names under the reserved <code>.example</code> zone, which the example and Break it use, are answered in your browser with fixed sample answers. Pressing Check server or Enter sends the address to the Tamperbox server, which resolves it, connects once from Eastern North America, asks for the server list status and a ping, and returns the observation. It never logs in, joins or sends a player name.</div> ## What the tool answers 1. **Where does the game connect?** The SRV record, if there is one, or the name on port 25565, and the address it resolves to. 2. **Does a Java Edition server answer there?** Online, refused, no answer, or something that is not a Minecraft server. 3. **What does it say about itself?** Message of the day, players online and the maximum, version name and protocol number, and whether it enforces secure chat. 4. **How fast is it?** The TCP connect time and the status ping, drawn as the game's signal bars. ## Inputs ### A server address `play.example.org`, `example.org:25570`, `203.0.113.10` or `[2001:db8::10]:25565`. A pasted link keeps its host and port. Without a port, the check follows the SRV record, using the tool's bounded SRV lookup; with a port, it connects to that port and ignores the SRV record. A port outside 1 to 65535 is refused with a repair that removes it. Private, loopback, link-local, unique local and carrier-grade NAT addresses are refused in the browser: no server on the internet can reach them, and a home server must be checked by its public address. ### When it runs Only on Enter or the Check server button. Adding spaces around the input keeps the current result; a changed address stages a new check and waits. A sample name under `.example` runs at once because it costs nothing. ## Reading the result ### Verdict and chips Online: "Online with N of M players", then the version, the ping and, when used, the SRV target. A full server is a warning. Offline outcomes read "Offline: … refused the connection", "No answer from …", "Not a Java server at …" or "Unavailable: … says it is not running". Chips give the player count, the version and "Uses SRV". ### Findings Directly under the verdict, worst first; see the [Finding reference](#finding-reference). ### The server list entry The server as the game's multiplayer list draws it: an initial in place of the icon (icons are not fetched), the address, the message of the day with its formatting codes removed, the player count with a fill bar, and the signal bars with the ping. ### How it answered The address entered, the SRV record (or why it was not used), the address and port connected to, the TCP connect time, the status ping, the version, the protocol number with the release it belongs to where that is certain, the secure chat flag, and the region the check ran from. ### History History records input changes made by Break it and Heal it. It appears after the complete result and before Take it further. Revert undoes the newest change; Reset input returns to the input before the first retained change. Restore input before this break is also available in Heal it when there is a change to undo. Restoring does not create another history entry. This history is held in the page and disappears on reload. Restoring a live target stages it for the run button; reserved samples can render immediately. Typing or pasting a different input starts a new history. ### Take it further These links carry values derived from the current result. A link is absent when its required evidence is missing; the tool does not invent a target. | Destination | Value and condition | | --- | --- | | [SRV Lookup](https://docs.tamperbox.dev/tools/srv-lookup/) | `_minecraft._tcp.<host>` for a live hostname entered without a port | | [TCP Ping](https://docs.tamperbox.dev/tools/tcp-ping/) | The connected address and game port, for live results | | [ASN Lookup](https://docs.tamperbox.dev/tools/asn-lookup/) | The server address, when available | Reserved sample results offer only the derived links supported by local sample data. A live destination applies its own input rules; measurement tools still wait for an explicit run. ### What this result means Six cards explain the current findings: Ask your agent, In plain words, What does it mean?, What good looks like, How to fix it, and Tool limitations. Expand a card to read the explanation and its method or guide link. Copying an agent prompt does not run another check. The cards interpret the evidence already shown; they are not an additional measurement or an independent confirmation. When the input is cleared, a check fails, or no result is available, result-specific cards clear and contextual links disappear. Read the verdict before relying on a card, and distinguish a missing observation from a confirmed negative result. ## Method ### 1. Following the SRV record When no port is given and the host is a name, the server asks DNS for SRV records at `_minecraft._tcp.<name>` ([RFC 2782](https://www.rfc-editor.org/rfc/rfc2782#page-2), "The format of the SRV RR"). An answer with more than 32 records, or with a priority or weight outside 0 to 65535, is refused as invalid. The selection approximates RFC 2782's usage rules ([page 6](https://www.rfc-editor.org/rfc/rfc2782#page-6)): keep the records with the lowest priority, then pick one at random in proportion to its weight ([page 5](https://www.rfc-editor.org/rfc/rfc2782#page-5)), or uniformly when all weights are zero. The implementation is not an exact RFC selection algorithm: zero-weight entries receive no chance when positive weights exist. When the positive weight total is smaller than the number of candidates, its random range can also leave no target selected, causing a failed lookup. A failure in this case is not evidence that every listed server is down. A target of `.` stops the check with "Unavailable", because, in the RFC's words, "A Target of "." means that the service is decidedly not available at this domain" ([page 4](https://www.rfc-editor.org/rfc/rfc2782#page-4)). No SRV record means the name itself on port 25565. A DNS failure other than "no such record" is reported as an error rather than silently falling back. The check tries one target. It does not fall back to the next target when the chosen one fails, so a network with several SRV targets of equal priority can show different results on different checks. ### 2. Resolving and connecting The target name must resolve to between 1 and 64 addresses, all public; the first is used. The server opens one TCP connection from Eastern North America. The time to complete the handshake is the TCP connect time. The whole exchange must finish within 5 seconds of starting and the request within 7 seconds. ### 3. Server List Ping On connect, the server sends the two packets of the Java Edition status exchange, as documented in the [Server List Ping](https://minecraft.wiki/w/Java_Edition_protocol/Server_List_Ping) protocol description: a handshake with protocol number `-1` (asking for status without claiming a client release), the address and port as the player typed them, and the next state "status", followed by an empty status request. The original name and port are sent, not the SRV target, because proxies and hosting panels use them to pick the virtual server. The answer must be one framed packet with id 0 holding UTF-8 JSON, with a string `version.name`, an integer `version.protocol`, and non-negative integer `players.online` and `players.max`; anything else is "Not a Minecraft status reply". The message is read from `description`, as a plain string or a text component with `extra` parts, and its `§` formatting codes are removed. `enforcesSecureChat` is reported when the server sends it. Responses are limited to 256 KiB in total and 128 KiB per packet. Player samples and the server icon are ignored. Then the server sends a ping packet with eight random bytes and times the matching pong. A server that answers the status but not the ping is still online, with "No status ping". ### 4. Outcomes | Outcome | Socket or protocol event | Verdict | | --- | --- | --- | | Online | Status JSON read | Online with N of M players | | Refused | `ECONNREFUSED` | Offline: refused the connection | | No answer | No connection or no reply within 5 seconds | No answer | | Unreachable | `ENETUNREACH`, `EHOSTUNREACH` | No answer | | Not Minecraft | Connected, but the reply is not a status packet, or the connection closed | Not a Java server | | Unavailable | SRV target is `.` | Unavailable: says it is not running | ### 5. Signal bars and releases The bars follow the game client's thresholds: five under 150 ms, four under 300 ms, three under 600 ms, two under 1000 ms, one above, none without a ping. Protocol numbers map to releases only where the mapping is certain (for example 47 is 1.8 to 1.8.9, 769 is 1.21.4); other numbers are shown as reported. A protocol below 754 (1.16.4) raises "An older game version", because current clients join such a server only through a version translation layer. <span id="standards"></span> ## Standards and conformance | Specification | Parts used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782) DNS SRV | [Format](https://www.rfc-editor.org/rfc/rfc2782#page-2), [target "."](https://www.rfc-editor.org/rfc/rfc2782#page-4), [weight](https://www.rfc-editor.org/rfc/rfc2782#page-5), [usage rules](https://www.rfc-editor.org/rfc/rfc2782#page-6) | Lowest priority, weighted random choice, "." means unavailable | One target is tried; no fallback to other targets. Obsoletes [RFC 2052](https://www.rfc-editor.org/rfc/rfc2052) | | [RFC 9293](https://www.rfc-editor.org/rfc/rfc9293) TCP | [3.5](https://www.rfc-editor.org/rfc/rfc9293#section-3.5) | Connect time is the handshake | | | [Server List Ping](https://minecraft.wiki/w/Java_Edition_protocol/Server_List_Ping) (community protocol documentation; there is no formal standard) | Handshake, status request and response, ping and pong | Modern status exchange (1.7 and later) | The legacy pre-1.7 ping and Bedrock's UDP protocol are not implemented | | [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3), [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598#section-4) | as listed | Private and shared addresses are refused | | ## Finding reference | Finding | Severity | What it means for players | Fix | | --- | --- | --- | --- | | Connection refused | FAIL | "Connection refused": nothing listens on the port | Start the server; check server-port; check the port forward | | No answer within 5 seconds | FAIL | "Timed out": stopped, firewalled, or no port forward | Allow TCP on the port; forward it; check the server is up | | Not a Minecraft status reply | FAIL | Another program is on the port, or a proxy blocks status | Check the port and the proxy's listener | | Service unavailable (verdict) | FAIL | The game stops at the record and cannot join by this name | Point the SRV record at the real host and port, or remove it | | The server is full | CHECK | "The server is full" until someone leaves | Raise max-players or grant a bypass permission | | Port 19132 (or 19133) is Bedrock's default | CHECK | A Bedrock server cannot be checked this way | Use the Java port, or test Bedrock in the game | | Found through an SRV record | INFO | Players can type the name without a port | Keep the record in step with the server | | An older game version | INFO | Current clients need a translation layer to join | Update the server or add ViaVersion | | No status ping | INFO | The game shows no signal bars | Usually harmless on old servers and some proxies | | Reported by the server | INFO | Version, players and message are unverified | | ## Guide ### Friends see "Connection refused" 1. Start the server and wait for "Done" in its console. 2. Check `server-port` in `server.properties` matches the port players use. 3. For a server at home, forward that TCP port in the router to the computer running it; the [Open Port Checker](https://tamperbox.dev/open-port-checker) tests the forward from outside. 4. Check again here. ### Friends see "Timed out" The connection is dropped before it reaches the server: a firewall on the computer, a missing port forward, carrier-grade NAT at the provider (your router's WAN address starts with 100.64 to 100.127), or a server that is off. ### Players must type a port Add an SRV record so the name alone works: ``` _minecraft._tcp.example.org. 3600 IN SRV 0 5 25577 mc.example.org. ``` Confirm it without Tamperbox: ```sh dig +short SRV _minecraft._tcp.example.org ``` The answer lists priority, weight, port and target. Then check the name here without a port: "How it answered" should show the SRV target. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | Server full | `full.harbor-supply.example` | 20 of 20 players and the full-server warning | | Old server, no ping | `old.harbor-supply.example` | Protocol 47 (1.8) and a server that skips the ping | | Offline | `down.harbor-supply.example` | A refused connection and its fix | | Bedrock address | `bedrock.harbor-supply.example:19132` | The Bedrock port warning with a timeout | | Private address | `192.168.1.50` | The refusal in the browser; nothing is sent | | Port out of range | your server with port 99999 | The port error and the repair without the port | ## Worked example The opening input is `play.harbor-supply.example`, a reserved sample survival server answered locally. Read its message, reported version and player counts as fixture data. The sample does not contact a real game server or establish that any player can join. Replace it with a public Java Edition server and press Check server. When no explicit port is supplied, inspect whether an SRV target was selected and which address and port were actually contacted. Compare TCP connect time with status ping: the latter includes the application-level pong exchange. An online result means a valid status reply arrived. Whitelists, authentication, protocol compatibility and gameplay performance can still prevent a player from joining. A full-server fixture illustrates the capacity warning, while a reply without pong remains online with no status-ping timing. ## For agents The Tamperbox MCP server runs the same check. Search its catalog for `minecraft_server_status`, inspect the input schema, and call it with the host and, only when the player uses one, the port. Each call spends one probe. Keep these warnings with any conclusion: - Online here does not mean a player can join: whitelists, versions and authentication are not tested. - Players, version and message are self-reported. - Bedrock servers cannot be checked. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/), and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the input travels. [TCP Ping](https://docs.tamperbox.dev/tools/tcp-ping/) measures the game port from three regions. ### Transfers to another tool Explicit sibling-tool controls can carry the current input or observed address to another page. The shared navigation stores that value temporarily in tab-scoped `sessionStorage`, accepts a transfer for at most one minute, and puts a random transfer token in the URL fragment. The input itself is not placed in the URL. The receiving page consumes the transfer and applies its own input rules; tools with a manual Run button still require that action for live checks. This is not a saved result, and the destination can send the value to the services it needs. Ordinary edits and lookups do not create a durable report archive. ## Limits - Java Edition only; Bedrock uses UDP. - One check from Eastern North America; one SRV target, no fallback. - The legacy pre-1.7 status ping is not implemented. - Names that resolve to private or reserved addresses are refused. - Sample answers under `.example` are fixed and labelled. - The page keeps results in memory. Explicit transfers to another tool use temporary session storage. ## References - [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782), A DNS RR for specifying the location of services (DNS SRV): the record format, target ".", the weight field and the usage rules (pages 2 to 6). Obsoletes [RFC 2052](https://www.rfc-editor.org/rfc/rfc2052). - [RFC 9293](https://www.rfc-editor.org/rfc/rfc9293), Transmission Control Protocol: section 3.5. - [Java Edition protocol: Server List Ping](https://minecraft.wiki/w/Java_Edition_protocol/Server_List_Ping), community documentation of the status exchange. - [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3), [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598#section-4): private and shared address space. --- # Mixed Content & Cookie Checker How the Mixed Content & Cookie Checker fetches or reads a page, sorts every insecure address by what browsers do with it, judges every Set-Cookie header, and how to fix and verify each finding. Canonical: https://docs.tamperbox.dev/tools/mixed-content-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public HTTP or HTTPS address on port 80 or 443, or the page's HTML, optionally preceded by its response headers and a blank line Outputs: A verdict naming the insecure addresses and the cookies that need attention, chips, findings worst first, the insecure addresses grouped by browser behaviour with tag and line, every cookie with its attributes and notes, and corrected Set-Cookie lines Limitations: Only the first 512 KiB of the HTML as served is read with a tag scanner; resources added by scripts, addresses inside external style sheets and requests made inside frames are not seen, and upgraded addresses are not tested over HTTPS The tool page is [tamperbox.dev/mixed-content-checker](https://tamperbox.dev/mixed-content-checker). It opens by fetching `tamperbox.dev` live, answers in one sentence whether the page loads anything over plain HTTP and how its cookies fare, and lists the evidence under it. This page is the long version: what is fetched, every rule the page applies, what each finding means, and how to fix and verify each one. <div class="tb-callout"><strong>Where processing happens:</strong> an address is sent to the Tamperbox server, which fetches the page once, following up to 10 redirects, and returns the headers of every response and the first 512 KiB of HTML. Cookie values are replaced on the server by their length, so only names and attributes reach your browser. Pasted HTML and headers are read in your browser and never uploaded. History and tool-to-tool transfers remain in the browser; see Browser transfers below.</div> ## What the tool answers Four questions, in the order a browser meets them: 1. **Is the page itself on HTTPS?** If the final address is `http://`, mixed content does not apply; the whole page is exposed, and that is the finding. 2. **What does the page load over plain HTTP?** Each `http://` address in the HTML, sorted by what browsers do: block it, upgrade it to `https://`, or warn before a form sends. 3. **Does a policy soften it?** A Content-Security-Policy with `upgrade-insecure-requests`, and a `<base href>` that turns relative addresses insecure. 4. **Are the cookies safe?** Every Set-Cookie header, on the final response and on each redirect, judged for what a browser rejects, what it exposes and what it merely notes. The verdict sentence answers the second and fourth questions; the chips count blocked, upgraded and form addresses and rejected or weak cookies, and each chip scrolls to its section. Findings under the verdict list the problems worst first, with passes folded into one line. ## Inputs The field takes three forms. What runs depends on the first characters of the text. | Input | Recognised by | What runs | Where | | --- | --- | --- | --- | | An address | anything that is not HTML or a header block | one page fetch, up to 10 redirects | Tamperbox server | | HTML | starts with `<` after leading whitespace | tag scan and classification | your browser | | Headers, blank line, HTML | starts with a status line or header lines | cookie checks, CSP read, then the HTML scan | your browser | ### An address `example.com`, `https://www.example.com/shop` or a full address with a query. The fetch starts when you stop typing, or on Enter. An address without a scheme is fetched over `https://`. The parser refuses, with a message in the field, an address with spaces, a scheme other than `http` or `https`, an IP address, a host without a top-level domain, a port other than 80 or 443, and a user name or password; the last two offer a repair under Heal it. The server repeats these checks for the input and every redirect target and requires each host to resolve to public addresses only. It sends `Accept: text/html,application/xhtml+xml;q=0.9,*/*;q=0.8` with a fixed user agent and no cookies. If the final response is not `text/html` or `application/xhtml+xml`, its body is discarded and only headers and cookies are checked. ### Pasted HTML and headers Paste the page source, or the output of `curl -si https://example.com/`: headers first, a blank line, then the HTML. Only the last response's headers are used, so cookies set on a redirect in pasted output are not read. Pasted source is treated as an HTTPS page at an unknown address, so relative addresses never count as insecure. Files (`.html`, `.htm`, `.txt`) up to 2 MiB can be dropped or opened and are read the same way. ### What the page does to pasted text The shared input cleaner runs on paste, drop and Enter. This is a page tool, so a pasted full address stays whole (path and query included) rather than being cut to a host; quotes and angle brackets around it are dropped. Text that is neither an address nor HTML nor headers stays exactly as pasted and the parser's error explains it. Break it and Heal it loads are never rewritten. ## Reading the result ### Verdict and chips The verdict leads with the count of insecure addresses and what browsers do with them, or "No mixed content on" the host, or "Plain HTTP page." The second line counts the cookies that need attention and how many browsers reject. Copy result copies the verdict and evidence as text. ### Findings One line per problem class: each group of insecure addresses, each cookie rule broken (with the cookie names), the plain-HTTP page, an `http://` base, and notes such as "upgrade-insecure-requests is set". Informational cookie notes stay with their cookie in the Cookies section. The count on the right says how many findings need fixing. ### Insecure addresses Grouped into Blocked by browsers, Upgraded to https:// and Forms that send in plain text. Each row shows the tag and attribute (`<script src>`, `<img srcset>`, `<form action>`, `url()`), the resolved address with `http://` marked, and the line in the source. ### Cookies One row per Set-Cookie header, labelled "Set by the page" or "Set by redirect n" with the host. Attribute pills show what is present and what is missing; red marks a missing attribute that gets the cookie rejected. Notes under each cookie are its findings. ### Corrected Set-Cookie lines For every cookie a repair applies to, the same line with Secure, HttpOnly or the `__Host-` shape added. Live values appear as `[redacted:n]`; put your own value back. ### History and Take it further History logs every Break it, Heal it and Revert, newest first; Revert puts the earlier input back and Reset input returns to where you started. Take it further hands a derived value to another security check: the host of an insecure address or of a form target into the [SSL Certificate Checker](https://docs.tamperbox.dev/tools/ssl-checker/), to see whether that host serves HTTPS at all, and, when the fetch was redirected, the final address into the Security Headers checker and the final host into the certificate check. Reserved `.example` hosts are not linked. ### Browser transfers Explicit tool links temporarily place the transferred input in browser `sessionStorage`. The URL fragment carries a random token, not the input. The receiving page accepts that token once, for its destination path and for less than one minute, then removes it from the address. A same-origin browser channel can complete a transfer into another tab. Ordinary documentation links do not transfer input. When browser storage is unavailable, navigation still works but the input may need to be pasted again. ## Method ### Fetching the page The server follows redirects one hop at a time, up to 11 requests, re-validating every target, and keeps the first 524,288 bytes (512 KiB) of the final body. Every Set-Cookie header of every response is kept, with its value replaced by `[redacted:n]`, where n is the value's length, so the size rule still works. Authentication headers are dropped from the evidence. ### Is the page on HTTPS If the final address uses `http://`, the result is the Fail "The page itself is served over plain HTTP" and no address list is shown. The [Mixed Content](https://www.w3.org/TR/mixed-content/#terms) specification defines mixed content only for a document delivered over a secure connection; an HTTP page has no secure context to protect. ### Scanning the HTML The HTML is read as text by a tag scanner, not parsed into a DOM. Comments are skipped; the contents of `script`, `style`, `title`, `textarea`, `noscript`, `template` and `xmp` are not searched for tags (style text is searched for `url()`). At most 20,000 tags are read. Each candidate address is resolved against `<base href>` when present, otherwise against the page, as [RFC 3986, section 5](https://www.rfc-editor.org/rfc/rfc3986#section-5) describes, and kept only when the result starts with `http:`. Protocol-relative addresses such as `//cdn.example.com/a.js` resolve to HTTPS on an HTTPS page and are not flagged. ### Classifying each address The classification follows the two categories in [Mixed Content, section 3](https://www.w3.org/TR/mixed-content/#categories): upgradeable content, which browsers now fetch over HTTPS, and blockable content, which they refuse. | Group | Elements and attributes | Severity | | --- | --- | --- | | Blocked | `script src`, `iframe src`, `frame src`, `embed src`, `object data`, `link href` with rel `stylesheet`, `preload`, `modulepreload`, `prefetch` or `manifest`, font files (`.woff`, `.woff2`, `.ttf`, `.otf`, `.eot`) in `url()` inside `<style>`, image sets: `img` with `srcset` (its `src` and every candidate), and `img` or `source` inside `picture` | Fail | | Upgraded | `img src` outside `picture` and without `srcset`, `source` inside `audio` or `video`, `audio src`, `video src` and `poster`, `track src`, `link` with an `icon` rel, other `url()` in `<style>`, every `url()` in a `style` attribute | Info | | Form | `form action` resolving to `http://` | Check | ### Policies that change the reading If any Content-Security-Policy, from a header or a `<meta http-equiv>`, contains `upgrade-insecure-requests`, the Pass "upgrade-insecure-requests is set" is shown and each group notes that browsers try HTTPS first, as [Upgrade Insecure Requests, section 4](https://www.w3.org/TR/upgrade-insecure-requests/#delivery) describes. Blocked rows still count against the verdict, because the upgrade fails when the other host has no HTTPS. A `<base href>` written with `http://` is its own Check. ### Cookie rules Each Set-Cookie line is split on `;`; attribute names are case-insensitive, a leading dot on Domain is ignored, and Max-Age wins over Expires, because [RFC 6265, section 4.1.2.2](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.2) says: "If a cookie has both the Max-Age and the Expires attribute, the Max-Age attribute has precedence". A cookie on an HTTPS response without Secure is a Check: [section 4.1.2.5](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.5) states that "The Secure attribute limits the scope of the cookie to "secure" channels", so without it the cookie also travels on `http://`. A name matching `sess`, `sid`, `token`, `auth`, `login`, `jwt`, `csrf`, `xsrf` or `remember` without HttpOnly is a Check, since "The HttpOnly attribute limits the scope of the cookie to HTTP requests" ([section 4.1.2.6](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.6)). The Fails follow the rules current browsers enforce from [RFC 6265bis](https://datatracker.ietf.org/doc/draft-ietf-httpbis-rfc6265bis/): SameSite=None requires Secure, the `__Secure-` prefix requires Secure, the `__Host-` prefix requires Secure, `Path=/` and no Domain, and a name plus value over 4,096 bytes is ignored. ### Heal it For pasted HTML, "Rewrite n addresses to https://" replaces every flagged address written with `http://` by its `https://` form wherever that exact text appears, and scans again. "Fix n cookies" applies the corrected lines to the pasted headers. Neither requests anything; test each address before publishing. ## Standards and conformance ### Mixed Content (W3C) Implemented: the secure-context precondition and the blockable and upgradeable categories of [Mixed Content](https://www.w3.org/TR/mixed-content/#categories), evaluated statically on the HTML. Where it stops: browsers decide by request destination at fetch time; the tool decides by tag and attribute. Image sets follow the specification's [upgradeable set](https://www.w3.org/TR/mixed-content/#category-upgradeable), which excludes requests whose initiator is `imageset`: an `img` with `srcset` and any `img` or `source` inside `picture` are listed as blocked, not upgraded. It still labels `track` and `url()` in a `style` attribute as upgraded, while the upgradeable set is images, audio and video only, so a browser may block a `track` or an inline-style font the tool lists as upgraded. Requests made by scripts, workers, `fetch()`, external style sheets and documents inside frames are not seen. The specification has replaced the earlier Level 1 optionally-blockable model; older browsers may block images instead of upgrading them. ### Upgrade Insecure Requests (W3C) Implemented: detection of the directive in any delivered policy, header or `meta`, per [section 4](https://www.w3.org/TR/upgrade-insecure-requests/#delivery). Not modelled: navigation upgrades and the directive's effect inside frames. The tool reports the directive but does not lower severities, by design. ### RFC 6265 and RFC 6265bis Implemented from [RFC 6265](https://www.rfc-editor.org/rfc/rfc6265) (Proposed Standard, the current RFC): attribute parsing ([5.2](https://www.rfc-editor.org/rfc/rfc6265#section-5.2)), Max-Age precedence ([4.1.2.2](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.2)), Secure ([4.1.2.5](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.5)), HttpOnly ([4.1.2.6](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.6)) and Domain widening ([4.1.2.3](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.3)). Stricter than RFC 6265 and taken from the [RFC 6265bis](https://datatracker.ietf.org/doc/draft-ietf-httpbis-rfc6265bis/) draft that browsers ship: SameSite and its Lax default, the prefixes, the 4,096-byte name-plus-value limit (RFC 6265 [section 6.1](https://www.rfc-editor.org/rfc/rfc6265#section-6.1) only sets a minimum a user agent should store) and the 400-day lifetime cap. Not checked: Path matching against the page, public-suffix Domain rejection, cookie count per domain, and what the server does with the cookie. ### Partitioned cookies and HTTP The Partitioned note follows the [CHIPS draft](https://datatracker.ietf.org/doc/draft-cutler-httpbis-partitioned-cookies/). HTTP semantics for headers and redirects follow [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110#section-15.4). ## Finding reference ### Page and addresses | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | The page itself is served over plain HTTP | Fail | [Mixed Content, terms](https://www.w3.org/TR/mixed-content/#terms) | Everything on the page can be read and changed on the network | Serve HTTPS and redirect `http://` to it | | n insecure addresses blocked by browsers | Fail | [Mixed Content, categories](https://www.w3.org/TR/mixed-content/#categories) | Scripts, styles, frames, fonts or objects never load | Use `https://` or relative addresses; self-host if the other host has no HTTPS | | n forms send in plain text | Check | [Mixed Content, 7.1](https://www.w3.org/TR/mixed-content/#requirements-forms) | Browsers warn; typed data travels unencrypted | Point `action` at HTTPS | | `<base href>` uses http:// | Check | [RFC 3986, 5.1](https://www.rfc-editor.org/rfc/rfc3986#section-5.1) | Every relative address becomes insecure | Use `https://` or remove the tag | | n insecure addresses upgraded to https:// | Info | [Mixed Content, categories](https://www.w3.org/TR/mixed-content/#categories) | Loads over HTTPS if the host serves it there | Rewrite to `https://` | | upgrade-insecure-requests is set | Pass | [Upgrade Insecure Requests, 4](https://www.w3.org/TR/upgrade-insecure-requests/#delivery) | Browsers try HTTPS first | Keep it as a safety net | | No HTML in the input / Cookies need the response headers | Info | none | Part of the evidence is missing | Paste headers, a blank line, then HTML | ### Cookies browsers reject | Finding | Source | Fix | | --- | --- | --- | | SameSite=None without Secure | [RFC 6265bis](https://datatracker.ietf.org/doc/draft-ietf-httpbis-rfc6265bis/), SameSite | Add Secure, or use SameSite=Lax | | __Host- rules broken | RFC 6265bis, cookie name prefixes | Secure, `Path=/`, no Domain | | __Secure- cookie without Secure | RFC 6265bis, cookie name prefixes | Add Secure | | Cookie is n bytes | RFC 6265bis, storage limits; [RFC 6265, 6.1](https://www.rfc-editor.org/rfc/rfc6265#section-6.1) | Keep an identifier, store data server-side | | Cookie has no name | [RFC 6265, 5.2](https://www.rfc-editor.org/rfc/rfc6265#section-5.2); RFC 6265bis section 5.6 instead accepts a nameless cookie with a value | Give it a name | ### Cookies to tighten and notes | Finding | Severity | Source | Meaning | | --- | --- | --- | --- | | Sent over plain HTTP too | Check | [RFC 6265, 4.1.2.5](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.5) | Missing Secure on an HTTPS response | | Readable by scripts | Check | [RFC 6265, 4.1.2.6](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.6) | Session-like name without HttpOnly; a name-based hint | | No SameSite | Info | RFC 6265bis, SameSite | Treated as Lax | | Third-party cookie | Info | [CHIPS](https://datatracker.ietf.org/doc/draft-cutler-httpbis-partitioned-cookies/) | SameSite=None without Partitioned; dropped where third-party cookies are blocked | | Shared with every *.domain host | Info | [RFC 6265, 4.1.2.3](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.3) | Domain widens it to subdomains | | Expires in n days | Info | RFC 6265bis, lifetime cap | Over 400 days; browsers cap it | | Already expired | Info | [RFC 6265, 4.1.2.1](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.1) | This header deletes the cookie | | Unknown attribute | Info | [RFC 6265, 5.2](https://www.rfc-editor.org/rfc/rfc6265#section-5.2) | Ignored by browsers | ## Guide ### A blocked script, style sheet or frame 1. Find where the address is written: the line number points at the tag; search templates, theme settings, CMS content and third-party snippets for the `http://` text. 2. Open the address with `https://` in a browser. If it loads, change the reference. If not, host the file yourself or replace the provider. 3. Check the page again until the Blocked group is gone, and open the browser console on the live page to catch requests made by scripts, which this scan cannot see. ### A form posting over HTTP Change `action` to the HTTPS endpoint, or to a relative address on your own site. For a third-party form service, use the HTTPS endpoint it documents, then submit once and confirm no warning appears. ### Upgraded images and media Nothing is broken today if the host serves HTTPS. Rewrite the addresses anyway, so the page does not rely on browser behaviour, and add `Content-Security-Policy: upgrade-insecure-requests` as a safety net. ### Cookie attributes Copy the line from Corrected Set-Cookie lines into the framework's cookie settings rather than editing headers by hand, so every response gets the attributes. Use the `__Host-` prefix for session cookies: the browser then enforces Secure, `Path=/` and no Domain. Leave HttpOnly off a cookie your own scripts must read. ### Reproduce the check outside Tamperbox | Command | Confirms | | --- | --- | | `curl -sI https://example.com/ \| grep -i '^set-cookie'` | the cookies and attributes the page sets | | `curl -s https://example.com/ \| grep -noE '(src\|href\|action\|poster)="http://[^"]+'` | `http://` addresses in the HTML, with line numbers | | `curl -sI https://example.com/ \| grep -i content-security-policy` | whether `upgrade-insecure-requests` is delivered | The browser's developer tools are the final check: the console reports each blocked request, and the Application panel shows which cookies were stored or rejected. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | Insecure script | your page with an `http://` script on its own host added | Blocked group, Fail | | Form posts over HTTP | your page with a subscribe form posting to `http://` | Form group, Check | | Cookie without Secure | your headers plus `session_id` with HttpOnly only | Sent over plain HTTP too | | SameSite=None, no Secure | your headers plus `cart` with SameSite=None | rejected cookie, Fail | | Plain HTTP page | `http://insecure.harbor-supply.example/` | plain-HTTP page, Fail | Each case builds on your own input; with nothing loaded yet, the reserved sample shop is used. Heal it offers the address rewrite and the cookie fix for pasted source, or "Restore input before this break". ## Worked example The page opens on `wikipedia.org`, fetched live by our server when the page loads. It was chosen because, when the candidates were compared, it redirected its apex to `www.wikipedia.org` and set cookies on both responses, which shows how the tool reads a redirect chain. Read the result top down: the verdict says whether any insecure address was found and how the cookies fare; the chips repeat the counts; the Insecure addresses section confirms that every resource uses `https://` or a relative address; the Cookies section lists each Set-Cookie header, labelled with the redirect hop or the page that set it, with its notes (a missing SameSite read as Lax, SameSite=None marking a third-party cookie, a Domain attribute that widens the cookie to every subdomain). When the fetch was redirected, Take it further carries the final address to the Security Headers Checker and the final host to the SSL Certificate Checker. The cookies, their attributes and the redirect belong to the site and can change at any time, so no values are reproduced here. To see every group at once, enter the reserved sample `www.harbor-supply.example`, which is answered in your browser: a chat widget script from `widgets.ticketdesk.example` is blocked, a partner badge on `cdn.harbor-supply.example` is upgraded, the newsletter form posts to `newsletter.bulkpost.example` in plain text, one of three cookies is rejected (SameSite=None without Secure) and a session cookie lacks Secure and HttpOnly. The Corrected Set-Cookie lines show both repairs. ## For agents The Tamperbox MCP server exposes `search` and `execute`. Use `execute` to call `POST /v1/tools/mixed_content_checker` with a full public `url`; it returns `evidence` (final `url`, `status`, `headers` with redacted cookies, `redirects`, `html`, `truncated`) and `report` (`https`, `upgrade`, `base`, `items` with `tag`, `attr`, `url`, `line` and `kind`). For HTML you already have, `mixed_content_analyze` takes `input`, optional `headers` and `url`, and returns `report`, `cookies` and, with `upgrade`, the rewritten HTML; `cookie_analyze` judges one Set-Cookie value. Apply the rules in [Method](#method) and keep these warnings: - The scan is static: it does not execute scripts or prove what a browser loads. - Upgraded addresses are not tested over HTTPS. - A live fetch is one observation from one place at one moment. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) for the calling pattern. ## Limits - First 512 KiB of HTML, at most 20,000 tags, up to 10 redirects, ports 80 and 443, public hosts only. - Script-inserted resources, external style sheets, frames' own content and service workers are not seen. - Addresses written inside scripts or JSON are not found. - Pasted input uses only the last response's headers and is assumed to be HTTPS. - The session-cookie name match is a hint; Path and public-suffix rules are not checked. - History is a browser interaction record, not server monitoring. Explicit tool links use temporary browser storage as described in [Browser transfers](#browser-transfers). ## References - [Mixed Content](https://www.w3.org/TR/mixed-content/), W3C Candidate Recommendation Draft; sections used: [terms](https://www.w3.org/TR/mixed-content/#terms), [categories](https://www.w3.org/TR/mixed-content/#categories) and [form submission](https://www.w3.org/TR/mixed-content/#requirements-forms). - [Upgrade Insecure Requests](https://www.w3.org/TR/upgrade-insecure-requests/), W3C Candidate Recommendation; section used: [4, delivery](https://www.w3.org/TR/upgrade-insecure-requests/#delivery). - [RFC 6265, HTTP State Management Mechanism](https://www.rfc-editor.org/rfc/rfc6265), Proposed Standard; to be obsoleted by RFC 6265bis. Sections used: [4.1.2.1](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.1), [4.1.2.2](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.2), [4.1.2.3](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.3), [4.1.2.5](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.5), [4.1.2.6](https://www.rfc-editor.org/rfc/rfc6265#section-4.1.2.6), [5.2](https://www.rfc-editor.org/rfc/rfc6265#section-5.2) and [6.1](https://www.rfc-editor.org/rfc/rfc6265#section-6.1). - [draft-ietf-httpbis-rfc6265bis](https://datatracker.ietf.org/doc/draft-ietf-httpbis-rfc6265bis/), Internet-Draft; SameSite, cookie name prefixes, size and lifetime limits. - [draft-cutler-httpbis-partitioned-cookies](https://datatracker.ietf.org/doc/draft-cutler-httpbis-partitioned-cookies/), Internet-Draft; the Partitioned attribute. - [RFC 3986, URI Generic Syntax](https://www.rfc-editor.org/rfc/rfc3986), Internet Standard; sections used: [5](https://www.rfc-editor.org/rfc/rfc3986#section-5) and [5.1](https://www.rfc-editor.org/rfc/rfc3986#section-5.1). - [RFC 9110, HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110), Internet Standard; section used: [15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4). --- # Mojibake Fixer How the Mojibake Fixer finds UTF-8 text that was read as Windows-1252 or Latin-1, repairs it once or several times over, leaves undamaged text alone, and reports what was lost for good. Canonical: https://docs.tamperbox.dev/tools/mojibake-fixer/ Updated: 2026-10-25 Applies to: tamperbox.dev, October 2026 Prerequisites: Garbled text, such as an export, a CSV or a web page showing sequences like é or ’ Outputs: A verdict, the repaired text with Copy and Use as input, and every repaired run with what it became Limitations: Only UTF-8 read as Windows-1252 or Latin-1 is repaired; U+FFFD marks data already lost; nothing is sent anywhere The tool page is [tamperbox.dev/mojibake-fixer](https://tamperbox.dev/mojibake-fixer). It opens on a café menu that was exported as UTF-8 and opened as Windows-1252. <div class="tb-callout"><strong>Where processing happens:</strong> your text is repaired in your browser and never uploaded, including text from a file you open or drop.</div> ## What the tool answers Was this text read in the wrong encoding, how many times, what did it say, and is any of it gone for good? ## How mojibake happens In UTF-8, é is the two bytes C3 A9. A program that reads those bytes as Windows-1252 shows each byte as one character: à and ©. A curly apostrophe is three bytes, E2 80 99, and becomes ’. If the garbled text is saved as UTF-8 and read wrongly again, it is damaged a second time: é becomes é. ## Method 1. Find each run of characters that Windows-1252 or Latin-1 can produce. 2. Turn the run back into the bytes those characters stand for. 3. Decode the bytes as strict UTF-8. Keep the result only if it decodes without error and does not leave stray control characters that a further pass cannot decode. 4. Repeat on the result, up to three passes, for text damaged more than once. Runs that do not decode stay as they were, so ordinary accented text and a genuine à in Portuguese are left alone. Every repaired run is listed with the pass that repaired it. ## Lost data The replacement character (U+FFFD, shown as �) means a program already replaced bytes it could not read. The original letters are gone; the fixer reports how many and does not guess. Get the text again from its source, read as UTF-8. ## Break it Garble once and Garble twice damage your own text the way a wrong encoding would, so you can see the repair work on it. Curly quotes, Lost data and Nothing wrong load short samples. Each break can be undone from Heal it. ## Prevent it Declare UTF-8 at every step: the export or file, the database connection's character set, the HTTP Content-Type header and the HTML meta charset. Import CSV files into a spreadsheet and choose UTF-8 instead of opening them by double-clicking. ## Finding reference | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | Repaired, read in the wrong encoding once | pass | [WHATWG Encoding](https://encoding.spec.whatwg.org/#windows-1252) | UTF-8 was read as Windows-1252 or Latin-1 | Declare UTF-8 where the text was read | | Damaged N times | check | [RFC 3629](https://www.rfc-editor.org/rfc/rfc3629) | Read wrongly, saved, and read wrongly again | Fix every step, not only the last | | Replacement characters | fail | [Unicode FAQ](https://www.unicode.org/faq/utf_bom.html) | Bytes were thrown away upstream | Export again from the source, read as UTF-8 | | No mojibake found | pass | | Nothing decodes as UTF-8 read as Windows-1252 | If text still looks wrong, it may be another encoding | ## Guide ### Repair a CSV export 1. Open the CSV in a text editor, copy the garbled part or the whole file (up to 512 KiB) and paste or drop it here. 2. Check What changed, then Copy the repaired text. 3. Next time, import the CSV into the spreadsheet and choose UTF-8 rather than opening it by double-click. ### Fix it at the source When text arrives garbled from a database, check the connection character set (for MySQL, utf8mb4). When it arrives from a web page or API, check the Content-Type charset. When it comes from email, check the part's charset header. ### Test that your system keeps UTF-8 intact Use Garble once on your own text to see what a wrong reading produces, then send real accented text through your import or export and compare it with what came out. ## Use it from an agent The `mojibake_fix` operation takes the text and returns the repaired text, with a warning when it was repaired or when data was lost. See the [MCP documentation](https://docs.tamperbox.dev/mcp/). ## References - [RFC 3629: UTF-8](https://www.rfc-editor.org/rfc/rfc3629) - [WHATWG Encoding Standard: windows-1252](https://encoding.spec.whatwg.org/#windows-1252) - [W3C: Character encodings for beginners](https://www.w3.org/International/questions/qa-what-is-encoding) --- # MTA-STS & TLS-RPT Checker How the checker follows what a sending server does, from the _mta-sts record to the policy file, MX coverage and TLS-RPT, every rule applied along the way, what each finding means for mail in transit, and how to fix and verify each one. Canonical: https://docs.tamperbox.dev/tools/mta-sts-checker/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain, or an MTA-STS policy file to paste Outputs: A verdict with PASS, CHECK and FAIL chips, the chain of checks a sender makes, the MX coverage table, a suggested policy file in enforce mode, and the findings with their fixes Limitations: No connection is made to any mail server, so STARTTLS support and MX certificates are not tested; senders cache a policy for max_age seconds, so changes take effect slowly The tool page is [tamperbox.dev/mta-sts-checker](https://tamperbox.dev/mta-sts-checker). It opens on a live check of `tamperbox.dev`; replace that domain to inspect your own. This page is the long version: what a sending server checks, every rule the tool applies at each step, what each finding means, and how to fix and verify each one. <div class="tb-callout"><strong>Where processing happens:</strong> a domain is sent to the Tamperbox server, which asks public DNS for the <code>_mta-sts</code> record, the MX records and the <code>_smtp._tls</code> record, and fetches one URL over HTTPS: <code>https://mta-sts.<domain>/.well-known/mta-sts.txt</code>. A pasted policy file is read line by line in your browser. Nothing is stored.</div> ## What the tool answers MTA-STS lets a receiving domain tell sending servers: deliver only to these mail servers, and only over TLS with a valid certificate. TLS-RPT lets senders report when they could not. The tool answers: 1. **Is a policy announced?** The `_mta-sts` TXT record with its id. 2. **Can the policy be fetched, and is it valid?** The file at the well-known URL, its version, mode, mx lines and max_age. 3. **Does the policy cover every mail server?** Each MX host against the policy's mx lines. 4. **Will you hear about failures?** The `_smtp._tls` TLS-RPT record and its report addresses. 5. **What should the policy say?** A suggested file in enforce mode that covers every MX host. It does not connect to any mail server, so STARTTLS support and MX certificates are not tested. ## Inputs ### A domain `example.com`. When you stop typing, or on Enter, the server makes the three DNS lookups and the one fetch in parallel. When all four fail because the lookup service is unavailable, the page reports an error rather than a missing policy. ### A policy file Paste the contents of `mta-sts.txt` (`version: STSv1`, `mode: enforce`, `mx: …`, `max_age: …`). It is checked in the browser, shown as "Policy file (pasted)". Publication, HTTPS hosting, MX coverage and TLS-RPT are not checked for a pasted file. ### An _mta-sts record Paste `v=STSv1; id=…` and only the record is checked, with a reminder that the policy itself lives in a file on HTTPS. ### Files Drop a `.txt` file anywhere on the page, or use Open file. It is read in the browser. ## Reading the result ### Verdict and chips The verdict names the outcome: no record, not protected (the file could not be fetched), the check failed with the first failure, policy withdrawn, testing only, enforced, or, for a pasted file, policy file checked. The chips show the mode, how many MX servers the policy covers, and the number of findings; each one is a button that scrolls to the section that explains it. ### Findings Everything found, worst first; passes fold into one line. The [finding reference](#finding-reference) lists them all. ### Take it further Links that carry a derived value into another tool: the TLS certificate of the primary MX server on port 25, DANE records for the same host and port, and DNSSEC on the zone. Each opens the destination with the value already in its box; nothing is put in the URL. ### History and Heal it History logs every Break it and Heal it change with what it replaced; Revert undoes the newest, Reset input returns to what you entered. Heal it offers the repairs the tool found for a pasted file: add the version line, correct a misspelt mode, set `max_age` to one week. ### The chain The four steps a sending server takes, in order, each with its status, what it found and the record or file it read: the policy record, the policy file, MX coverage, TLS reports. ### MX coverage One row per MX host with its preference, the policy line that covers it or "No matching line", and Covered or Not covered. ### Suggested policy file A policy in enforce mode built from the current one: existing mx lines that still match an MX host, every uncovered host added by name, and a `max_age` of a week or the current value when it is longer and valid. Hidden when no mx line can be derived. The note under it says to serve the file over HTTPS and change the id in the record afterwards. ## Method The checker follows the order in which a sending server discovers and applies a policy. Each rule below names the section of the specification it comes from; rules with no section are Tamperbox recommendations and are labelled as such. ### The _mta-sts record Source: [RFC 8461 section 3.1](https://www.rfc-editor.org/rfc/rfc8461#section-3.1). The record is read at `_mta-sts.<domain>`, a CNAME at that name is followed, and a record split into several strings is joined without spaces, as section 3.1 requires. Records that do not begin with `v=STSv1` are discarded, and the rest must number exactly one. The section is explicit about what happens otherwise: "If the number of resulting records is not one, or if the resulting record is syntactically invalid, senders MUST assume the recipient domain does not have an available MTA-STS Policy." Zero or two records give "Publish exactly one MTA-STS record." Within the record, `v` must be the first tag ("The TXT record MUST begin with the sts-version field") and `id` must be 1 to 32 letters or digits, the `1*32(ALPHA / DIGIT)` rule of the section 3.1 grammar, so an id written with dashes fails. A missing record is FAIL, `No record at _mta-sts.<domain>`, with a suggested record whose id is today's date followed by `01`. A lookup that could not be made (as opposed to one that returned nothing) is reported as unavailable and produces no finding. ### Fetching the policy file Source: [RFC 8461 sections 3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) and [3.3](https://www.rfc-editor.org/rfc/rfc8461#section-3.3). The server fetches one URL only, `https://mta-sts.<domain>/.well-known/mta-sts.txt`, the fixed path of section 3.2. It reports a failure when: - the response is a redirect: "HTTP 3xx redirects MUST NOT be followed" (section 3.3); - the status is not a success (section 3.3 accepts only 200; see [where the tool differs](#where-the-tool-differs-from-rfc-8461)); - the Content-Type is not `text/plain`: "senders SHOULD validate that the media type is "text/plain"" (section 3.2); - the body exceeds 64 KiB, the size section 3.3 suggests; - the whole lookup takes longer than eight seconds (section 3.3 allows a timeout and suggests one minute). Two refusals are Tamperbox safety rules with no RFC source: the host must resolve, and only to public addresses. No cookies, credentials or visitor headers are forwarded. A failed fetch gives FAIL, "No policy file", with the reason in the chain, and the verdict "Not protected". Section 3.3 states what a sender then does: with no cached policy, "senders MUST continue with delivery as though the domain has not implemented MTA-STS." ### Policy file rules Source: the field list and grammar of [RFC 8461 section 3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2). Each line must be `key: value`; any other line is FAIL, "Not a key: value line: X". | Rule | Severity | Title | Source | | --- | --- | --- | --- | | `version: STSv1` required | FAIL | version: STSv1 is missing | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | | `mode` must be `enforce`, `testing` or `none` | FAIL | mode: X | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | | `mode: testing` | CHECK | mode: testing | [5](https://www.rfc-editor.org/rfc/rfc8461#section-5); CHECK is Tamperbox's severity | | `mode: enforce` with no other problem | PASS | mode: enforce | [5](https://www.rfc-editor.org/rfc/rfc8461#section-5) | | At least one `mx:` line unless the mode is `none` | FAIL | No mx: lines | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) grammar | | Each `mx:` a host name or `*.` plus a host name, at most 253 characters | FAIL | Invalid MX pattern X | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2), [RFC 5321 4.1.2](https://www.rfc-editor.org/rfc/rfc5321#section-4.1.2) | | `max_age` a whole number of seconds from 0 to 31557600 | FAIL | max_age is missing or out of range | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | | `max_age` under 86400 | CHECK | max_age N s | none (Tamperbox recommendation) | | Repeated `version`, `mode` or `max_age`: first value wins | CHECK | Duplicate X field | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | #### Why mode decides the verdict Section 5 defines what each mode makes a sender do. Under enforce, "Sending MTAs MUST NOT deliver the message to hosts that fail MX matching or certificate validation or that do not support STARTTLS." Under testing, "messages may be delivered as though there were no MTA-STS validation failure", which is why testing is a CHECK and not a PASS. ### MX coverage Source: [RFC 8461 section 4.1](https://www.rfc-editor.org/rfc/rfc8461#section-4.1). The MX records are sorted by preference, lowest first, as [RFC 5321 section 5.1](https://www.rfc-editor.org/rfc/rfc5321#section-5.1) orders them, and every host is compared with the policy's mx patterns, case-insensitively and ignoring a trailing dot. Section 4.1 limits the wildcard: "the wildcard character '*' may only be used to match the entire left-most label in the presented identifier." So `*.mx.example.net` matches `a.mx.example.net`, never `mx.example.net` or `b.a.mx.example.net`. An uncovered host is FAIL under `mode: enforce` ("X is not in the policy": senders refuse to deliver to it, section 5) and CHECK otherwise (it would be refused once the policy enforces). Every host is checked, not only the preferred one, because [section 8.4](https://www.rfc-editor.org/rfc/rfc8461#section-8.4) warns that a misconfigured backup MX may only be discovered when the primary fails. A domain with no MX records, a failed MX lookup or a null MX (the single `0 .` record of [RFC 7505 section 3](https://www.rfc-editor.org/rfc/rfc7505#section-3), which says the domain accepts no mail) is FAIL, "MX coverage not established". ### TLS-RPT Source: [RFC 8460 section 3](https://www.rfc-editor.org/rfc/rfc8460#section-3). The record is read at `_smtp._tls.<domain>`; records that do not begin with `v=TLSRPTv1` are discarded and the rest must number exactly one: "If the number of resulting records is not one, senders MUST assume the recipient domain does not implement TLSRPT." `v` must come first and at least one `rua` destination must be present. Section 3 names the two supported schemes, "mailto" and "https", and the tool requires each destination to use one of them. A missing, duplicated or unparseable record is CHECK, "No TLS-RPT record", with a suggested record; a destination with another scheme is FAIL, "Invalid report address X"; a valid record is PASS, "TLS reports on". Reporting is optional in the specification, so its absence is not a FAIL. ### The suggested policy The suggested file is a Tamperbox construction, not an RFC rule. It is built only when at least one mx line can be derived. It uses `mode: enforce`, keeps the existing mx lines that still match an MX host (all of them when no MX hosts were read), adds every uncovered host by name, and sets `max_age` to the current value when it is valid and longer than a week, 604800 otherwise. The week follows section 3.2, which expects `max_age` "typically be in the range of weeks or greater". The note under it asks you to change the id after publishing the file, in the order [section 8.1](https://www.rfc-editor.org/rfc/rfc8461#section-8.1) gives: "Recipients SHOULD also update the HTTPS policy body before updating the TXT record". ## Standards and conformance The checker implements the discovery and policy rules of RFC 8461, the record rules of RFC 8460, and the MX rules of RFC 5321 and RFC 7505 that coverage depends on. Where the work happens: - **Looked up on our server.** The `_mta-sts`, MX and `_smtp._tls` records are resolved by the Tamperbox server through one public DNS-over-HTTPS resolver, following CNAME chains of up to eight hops. - **Fetched on our server.** The policy file is fetched once over HTTPS by the Tamperbox server, which returns the text to your browser. - **Parsed locally.** The record grammar, the policy file, MX coverage, TLS-RPT and the suggested policy are all evaluated in your browser, by the same code that checks a pasted file. It never opens an SMTP connection, so everything that happens between a sender and an MX host is outside what it can see. ### RFC 8461, SMTP MTA Strict Transport Security Status: Proposed Standard, September 2018, with no updating RFC. | Section | Requirement | What the tool does | | --- | --- | --- | | [3.1](https://www.rfc-editor.org/rfc/rfc8461#section-3.1) | One `v=STSv1` TXT record, version first, id of 1 to 32 letters or digits, strings joined, CNAMEs followed | Implemented as written for the version, id, count, joining and CNAMEs | | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | Fixed URL; `text/plain` (SHOULD); version, mode, max_age once, mx at least once unless mode is none | Implemented; the media type check is a hard failure, not a warning | | [3.3](https://www.rfc-editor.org/rfc/rfc8461#section-3.3) | Certificate valid for the `mta-sts` host; only 200; no redirects; no HTTP caching; timeout and size MAY | Redirects refused, 64 KiB cap, eight-second limit; the certificate is not inspected (below) | | [3.3](https://www.rfc-editor.org/rfc/rfc8461#section-3.3), [5.1](https://www.rfc-editor.org/rfc/rfc8461#section-5.1) | Senders cache a policy for up to max_age and apply a cached policy when discovery fails | Not modelled: each check is live and uncached; the verdict notes that cached policies may still apply | | [3.4](https://www.rfc-editor.org/rfc/rfc8461#section-3.4) | Never fetch a policy from the parent zone | Only the domain entered is checked | | [4.1](https://www.rfc-editor.org/rfc/rfc8461#section-4.1) | Every MX matches an mx pattern; the wildcard covers one left-most label | Implemented for every MX host | | [4.2](https://www.rfc-editor.org/rfc/rfc8461#section-4.2), [7.1](https://www.rfc-editor.org/rfc/rfc8461#section-7.1), [7.2](https://www.rfc-editor.org/rfc/rfc8461#section-7.2) | STARTTLS, a valid MX certificate, SNI, TLS 1.2 or later | Not tested; Take it further opens the TLS and DANE checks for the primary MX | | [5](https://www.rfc-editor.org/rfc/rfc8461#section-5) | Meaning of enforce, testing and none | Drives the verdict and the severity of uncovered hosts | | [8.3](https://www.rfc-editor.org/rfc/rfc8461#section-8.3) | `mode: none` withdraws the policy | Reported as a valid withdrawal, "Policy withdrawn" | #### The policy host certificate Section 3.3 says the Policy Host "MUST present an X.509 certificate that is valid for the "mta-sts" DNS-ID". The tool does not examine that certificate. The fetch relies on the TLS validation of the server platform, and a failed handshake surfaces as a generic lookup failure in the chain, not as a named certificate finding. Use the [SSL checker](https://tamperbox.dev/ssl-checker) on `mta-sts.<domain>` to see the certificate itself. ### Where the tool differs from RFC 8461 These differences were confirmed by running the parser on the inputs described. | Section | What the RFC says | What the tool does | | --- | --- | --- | | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | A duplicated version, mode or max_age is not an error: "all entries except for the first SHALL be ignored" | CHECK, "Duplicate X field"; the first value is kept, so testing followed by enforce remains testing | | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | Field names are case-sensitive (`%s"mode"`) and no space is allowed before the colon | Names are matched case-insensitively and a space before the colon is accepted, so `Mode : enforce` passes here | | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | Unknown fields "SHALL be ignored"; names may contain digits, `_`, `-` and `.` | Unknown names with only letters and `_` are ignored; a name with a digit, `-` or `.` is FAIL, "Not a key: value line" | | [3.1](https://www.rfc-editor.org/rfc/rfc8461#section-3.1) | Extension tags in the TXT record are allowed and ignored | A tag name with `-` or `.` is reported as a malformed record; spaces around `=` are accepted | | [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | An mx value is an RFC 5321 `Domain`, which may be a single label | Single-label patterns are FAIL, "Invalid MX pattern" | | [3.3](https://www.rfc-editor.org/rfc/rfc8461#section-3.3) | "Policies fetched via HTTPS are only valid if the HTTP response code is 200 (OK)." | Any 2xx status is accepted | #### max_age limits The bounds match section 3.2: a non-negative integer up to 31557600. The CHECK for values under 86400 is a Tamperbox recommendation; the RFC sets no lower bound, so `max_age: 0` is valid there and a CHECK here. Section 3.2 expects "weeks or greater", and [section 10.2](https://www.rfc-editor.org/rfc/rfc8461#section-10.2) says implementers "SHOULD prefer policy "max_age" values to be as long as is practical", which is where the one-week suggestion comes from. ### RFC 8460, SMTP TLS Reporting Status: Proposed Standard, September 2018. | Section | Requirement | What the tool does | | --- | --- | --- | | [3](https://www.rfc-editor.org/rfc/rfc8460#section-3) | One record at `_smtp._tls`, beginning `v=TLSRPTv1`, strings joined | Implemented | | [3](https://www.rfc-editor.org/rfc/rfc8460#section-3) | `rua` required, a comma-separated list of `mailto` or `https` URIs | Implemented; each destination is checked for one of the two schemes | | [3](https://www.rfc-editor.org/rfc/rfc8460#section-3) | Unknown fields "SHALL be ignored" | A field name containing `-` or `.` makes the record unparseable here, reported as "No TLS-RPT record" | | [3](https://www.rfc-editor.org/rfc/rfc8460#section-3) | Reports by mail carry a DKIM signature; the key SHOULD declare `s=tlsrpt` | Not checked | | [4](https://www.rfc-editor.org/rfc/rfc8460#section-4), [5](https://www.rfc-editor.org/rfc/rfc8460#section-5) | Report format and delivery | Out of scope: no reports are received or read | Two severity choices are Tamperbox's own. A duplicated or invalid record is folded into the CHECK "No TLS-RPT record" rather than named, because the RFC's consequence is the same as a missing one. An unsupported scheme is FAIL, although the RFC only says which schemes are supported; senders would have nowhere usable to send that report. ### RFC 5321 and RFC 7505, the MX records [RFC 5321](https://www.rfc-editor.org/rfc/rfc5321) (Draft Standard, October 2008, updated by RFC 7504) defines how senders find mail servers. [Section 5.1](https://www.rfc-editor.org/rfc/rfc5321#section-5.1) says MX preference "MUST be used in sorting", and the coverage table follows that order. The same section says that when no MX records exist, "the address is treated as if it was associated with an implicit MX RR, with a preference of 0, pointing to that host." The tool does not model the implicit MX: a domain without MX records is FAIL, "MX coverage not established", and the domain itself is not compared with the mx lines. [RFC 7505](https://www.rfc-editor.org/rfc/rfc7505) (Proposed Standard, June 2015) defines the null MX. [Section 3](https://www.rfc-editor.org/rfc/rfc7505#section-3) says "A domain that advertises a null MX MUST NOT advertise any other MX RR." The tool treats any `.` exchange as a null MX and stops; it does not report a null MX mixed with ordinary records as a separate error. ### RFC 9525, service identity RFC 8461 sections [3.3](https://www.rfc-editor.org/rfc/rfc8461#section-3.3), [4.1](https://www.rfc-editor.org/rfc/rfc8461#section-4.1) and [4.2](https://www.rfc-editor.org/rfc/rfc8461#section-4.2) refer to RFC 6125 for name matching. [RFC 9525](https://www.rfc-editor.org/rfc/rfc9525) (Proposed Standard, November 2023) obsoletes RFC 6125, so its rules now apply. [Section 6.3](https://www.rfc-editor.org/rfc/rfc9525#section-6.3) compares names label by label "using a case-insensitive ASCII comparison" and states that "A wildcard in a presented identifier can only match one label in a reference identifier." The mx matching applies both rules. RFC 8461 also requires the A-label form for internationalized names, and a pattern with non-ASCII characters is reported as an invalid MX pattern. Certificate name matching, the main subject of RFC 9525, is not performed, because no certificate is examined. ### RFC 8552 and RFC 8553, underscored names `_mta-sts` is listed in the "Underscored and Globally Scoped DNS Node Names" registry created by [RFC 8552 section 4.1](https://www.rfc-editor.org/rfc/rfc8552#section-4.1) (Best Current Practice, BCP 222). [RFC 8553](https://www.rfc-editor.org/rfc/rfc8553), the companion that corrected older specifications, does not update RFC 8461 or RFC 8460: neither appears in its Updates list, and its info page records no such relationship. The only effect on the tool is that the server accepts the underscore labels in both lookup names. ## Finding reference Each finding the checker can emit, grouped by the part of the setup it judges, with what it means for mail sent to the domain. The RFC section column links the rule behind each finding; "none" marks a Tamperbox recommendation that the specification does not set. ### The _mta-sts record The TXT record that tells senders a policy exists and which version to fetch. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | No record at _mta-sts.domain | FAIL | Senders never look for a policy | Publish v=STSv1; id=… | [RFC 8461 3.1](https://www.rfc-editor.org/rfc/rfc8461#section-3.1) | | Publish exactly one MTA-STS record. | FAIL | Senders cannot pick one | Keep one record | [RFC 8461 3.1](https://www.rfc-editor.org/rfc/rfc8461#section-3.1) | | The version tag must be first., An MTA-STS record starts with v=STSv1., id= must be 1 to 32 letters or digits. | FAIL | Senders ignore the record | Correct the record | [RFC 8461 3.1](https://www.rfc-editor.org/rfc/rfc8461#section-3.1) | | id=X (pasted record) | PASS | The record is valid | Change the id when the file changes | [RFC 8461 3.1](https://www.rfc-editor.org/rfc/rfc8461#section-3.1) | ### The policy file The file at `https://mta-sts.<domain>/.well-known/mta-sts.txt`, line by line. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | No policy file | FAIL | Senders treat the domain as having no policy | Serve the file at the well-known URL over HTTPS as text/plain | [RFC 8461 3.3](https://www.rfc-editor.org/rfc/rfc8461#section-3.3) | | version: STSv1 is missing | FAIL | Senders discard the policy | Add the line | [RFC 8461 3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | | mode: X (invalid) | FAIL | Senders discard the policy | Use enforce, testing or none | [RFC 8461 3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | | mode: testing | CHECK | Failures are reported but mail still delivers over plain text | Switch to enforce when reports are clean | [RFC 8461 5](https://www.rfc-editor.org/rfc/rfc8461#section-5) | | mode: enforce | PASS | Senders require TLS to a listed server | | [RFC 8461 5](https://www.rfc-editor.org/rfc/rfc8461#section-5) | | No mx: lines | FAIL | No server would be allowed | Add one mx line per host | [RFC 8461 3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | | Invalid MX pattern X | FAIL | Senders discard the policy | Fix the line | [RFC 8461 3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | | max_age is missing or out of range | FAIL | Senders discard the policy | Use seconds up to one year | [RFC 8461 3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | | max_age N s | CHECK | Protection lapses quickly | Use a week or more | none (Tamperbox recommendation) | | Not a key: value line: X | FAIL | Senders may discard the policy | Fix the line | [RFC 8461 3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) | ### MX coverage Whether every mail server the domain publishes is allowed by the policy. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | X is not in the policy | FAIL (enforce) or CHECK | Senders refuse that server, or will once enforced | Add mx: X | [RFC 8461 4.1](https://www.rfc-editor.org/rfc/rfc8461#section-4.1), [5](https://www.rfc-editor.org/rfc/rfc8461#section-5) | | MX coverage not established | FAIL | No usable MX servers | Publish MX records | [RFC 5321 5.1](https://www.rfc-editor.org/rfc/rfc5321#section-5.1), [RFC 7505 3](https://www.rfc-editor.org/rfc/rfc7505#section-3) | ### TLS reporting The `_smtp._tls` record that asks senders for daily failure reports. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | No TLS-RPT record | CHECK | You will not hear about failed connections | Publish v=TLSRPTv1; rua=mailto:… | [RFC 8460 3](https://www.rfc-editor.org/rfc/rfc8460#section-3); CHECK is Tamperbox's severity | | Invalid report address X | FAIL | Senders skip the address | Use mailto: or https: | [RFC 8460 3](https://www.rfc-editor.org/rfc/rfc8460#section-3) | | TLS reports on | PASS | Daily reports go to the listed addresses | | [RFC 8460 3](https://www.rfc-editor.org/rfc/rfc8460#section-3), [4.1](https://www.rfc-editor.org/rfc/rfc8460#section-4.1) | ## Guide ### Setting up MTA-STS from scratch 1. Publish a TLS-RPT record first: `_smtp._tls.<domain> TXT "v=TLSRPTv1; rua=mailto:tls-reports@<domain>"`, so you hear about problems from day one. 2. Create the host `mta-sts.<domain>` and serve `/.well-known/mta-sts.txt` over HTTPS with a certificate valid for that host, as `text/plain`, with no redirect. Start with `mode: testing`, one `mx:` line per MX host, and `max_age: 604800`. 3. Publish `_mta-sts.<domain> TXT "v=STSv1; id=<date>01"`. 4. Check the domain here: every step in the chain should pass, with "mode: testing" as the only CHECK. 5. After a week of clean TLS reports, change the mode to enforce, change the id, and check again. ### The policy file cannot be fetched The chain names the reason. The usual causes: the `mta-sts` host does not exist; the web server redirects every path to `www`; a static host serves `.txt` as `application/octet-stream`; the certificate does not cover the `mta-sts` host. Fix the one named, then check again. ### An MX server is not in the policy Add `mx: <host>` to the file; the suggested policy already includes every uncovered host. Change the id in the record so senders fetch the new file. When a wildcard covers a provider's servers, remember it covers one label only. ### Testing to enforce Read the TLS reports until they show no failures for every MX host, then change `mode: testing` to `mode: enforce` and the id. The suggested policy on the page is that file. ### Short or invalid max_age Use a week or more once the policy is stable; Heal it sets 604800 on a pasted file. Values above one year are invalid. ### Withdrawing a policy Publish `mode: none` with a new id and wait for the longest `max_age` you ever published before removing the record and the file. ### Break it cases Each case is built from the policy you pasted or the domain serves. | Case | What it does to the file | Heal it offers (pasted file) | | --- | --- | --- | | Missing version line | Removes `version:` | Add version: STSv1 | | No mx lines | Removes every `mx:` line | Nothing: add the lines yourself | | Unknown mode | Misspells the mode (`enforced`, `test`, `off`) | Change mode to enforce or testing | | max_age too short | Sets `max_age: 300` | Set max_age to one week | | max_age too long | Sets `max_age: 99999999` | Set max_age to one week | ## Worked example The page opens on a live check of `tamperbox.dev`. Its published records and findings can change over time. For the deterministic walkthrough below, enter `harbor-supply.example`. This reserved `.example` domain is answered from synthetic data in your browser; it sends no live lookup. Its record announces a policy (`v=STSv1; id=20261001T0000`), the file is in testing mode with `mx: mx1.inboxcloud.example`, `mx: *.mx.inboxcloud.example` and `max_age: 86400`, the MX records name `mx1.inboxcloud.example`, `alt1.mx.inboxcloud.example` and `backup.harbor-supply.example`, and TLS-RPT reports go to `tls-reports@harbor-supply.example`. **Testing only: senders report failures but still deliver over plain text.** Two of three MX servers are covered; the backup is not and would be refused once the policy enforces. The suggested policy adds `mx: backup.harbor-supply.example`, switches to enforce and raises `max_age` to a week. Replace the sample with your own domain and every section, card and link is rewritten for it. ## For agents The Tamperbox MCP server runs the same checks. Search its catalog for the MTA-STS operation, inspect the input schema, and call it with the domain. Keep the warning block with any conclusion: - No connection is made to any mail server; STARTTLS and MX certificates are not tested. - Senders cache a policy for `max_age` seconds; a change takes effect slowly, and a cached policy may still apply to a domain whose record has gone. - A wildcard mx line covers exactly one label. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the domain travels. ## Limits - DNS and HTTPS only; no SMTP connection. - One fetch of one URL, without following redirects. - A pasted file is checked for syntax; coverage and publication need the domain. - One DNS answer, from one public resolver, at one moment. - Nothing is stored. ## References - [RFC 8461, SMTP MTA Strict Transport Security (MTA-STS)](https://www.rfc-editor.org/rfc/rfc8461), Proposed Standard, September 2018, no updates. Sections used: [3.1](https://www.rfc-editor.org/rfc/rfc8461#section-3.1) for the TXT record, [3.2](https://www.rfc-editor.org/rfc/rfc8461#section-3.2) for the policy file, [3.3](https://www.rfc-editor.org/rfc/rfc8461#section-3.3) for fetching, [3.4](https://www.rfc-editor.org/rfc/rfc8461#section-3.4) for subdomains, [4.1](https://www.rfc-editor.org/rfc/rfc8461#section-4.1) for the one-label wildcard, [4.2](https://www.rfc-editor.org/rfc/rfc8461#section-4.2), [5](https://www.rfc-editor.org/rfc/rfc8461#section-5) and [5.1](https://www.rfc-editor.org/rfc/rfc8461#section-5.1) for the modes, [7.1](https://www.rfc-editor.org/rfc/rfc8461#section-7.1), [7.2](https://www.rfc-editor.org/rfc/rfc8461#section-7.2), [8.1](https://www.rfc-editor.org/rfc/rfc8461#section-8.1), [8.3](https://www.rfc-editor.org/rfc/rfc8461#section-8.3), [8.4](https://www.rfc-editor.org/rfc/rfc8461#section-8.4) and [10.2](https://www.rfc-editor.org/rfc/rfc8461#section-10.2). - [RFC 8460, SMTP TLS Reporting](https://www.rfc-editor.org/rfc/rfc8460), Proposed Standard, September 2018. Sections used: [3](https://www.rfc-editor.org/rfc/rfc8460#section-3) for the `_smtp._tls` record, [4](https://www.rfc-editor.org/rfc/rfc8460#section-4) and [4.1](https://www.rfc-editor.org/rfc/rfc8460#section-4.1) for the daily report, [5](https://www.rfc-editor.org/rfc/rfc8460#section-5) for delivery (not checked). - [RFC 5321, Simple Mail Transfer Protocol](https://www.rfc-editor.org/rfc/rfc5321), Draft Standard, October 2008, updated by RFC 7504. Sections used: [4.1.2](https://www.rfc-editor.org/rfc/rfc5321#section-4.1.2) for the `Domain` syntax of mx values, [5.1](https://www.rfc-editor.org/rfc/rfc5321#section-5.1) for MX ordering and the implicit MX. - [RFC 7505, A "Null MX" No Service Resource Record for Domains That Accept No Mail](https://www.rfc-editor.org/rfc/rfc7505), Proposed Standard, June 2015. Section used: [3](https://www.rfc-editor.org/rfc/rfc7505#section-3). - [RFC 9525, Service Identity in TLS](https://www.rfc-editor.org/rfc/rfc9525), Proposed Standard, November 2023, obsoletes RFC 6125, which RFC 8461 cites for name matching. Section used: [6.3](https://www.rfc-editor.org/rfc/rfc9525#section-6.3). - [RFC 8552, Scoped Interpretation of DNS Resource Records through "Underscored" Naming of Attribute Leaves](https://www.rfc-editor.org/rfc/rfc8552), Best Current Practice (BCP 222), March 2019. Section used: [4.1](https://www.rfc-editor.org/rfc/rfc8552#section-4.1). - [RFC 8553, DNS AttrLeaf Changes](https://www.rfc-editor.org/rfc/rfc8553), Best Current Practice (BCP 222), March 2019; it does not update RFC 8461 or RFC 8460. - [DANE checker](https://tamperbox.dev/dane-checker), the DNSSEC-based alternative for pinning MX certificates. --- # MX Lookup & Email Domain Checker How Tamperbox validates a mail domain, reads MX and address fallback records, identifies null MX, and explains what public routing evidence proves. Canonical: https://docs.tamperbox.dev/tools/email-domain/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain that might receive email Outputs: A routing verdict, findings, public MX or address evidence, provider hint and lookup limitations Limitations: Public DNS does not prove SMTP availability, mailbox existence or delivery, and cached or private answers may differ The tool page is [tamperbox.dev/email-domain](https://tamperbox.dev/email-domain). It opens on a live lookup of `tamperbox.dev`; replace that value to inspect your own domain. This guide documents the input cleanup, resolver path, classifications, evidence contract and independent checks. <div class="tb-callout"><strong>Where processing happens:</strong> pasted text is cleaned and validated in the browser. A valid domain is sent to the Tamperbox server, which asks a public DNS resolver for MX and, when required, A and AAAA records. Nothing is stored and no SMTP connection is opened.</div> ## What the tool answers The checker answers whether public DNS advertises a route for mail addressed to a domain. It distinguishes five materially different situations: valid MX records, an explicit null MX refusal, address-record fallback, no route, and an inconclusive lookup or malformed MX set. It also shows the evidence that produced the classification and a provider hint inferred from recognised MX hostnames. The answer is deliberately narrower than “does this email address work?” An MX record is a routing instruction. The tool never opens a socket to the target, sends a message, performs SMTP recipient validation, reads private DNS or proves that a mailbox exists. A green routing result therefore proves publication, not delivery. ## Inputs ### Domain names Enter a registrable-looking domain such as `example.com`. Capitals are lowered, one final dot is removed, full-width dot characters are normalised, and international labels are converted by the URL parser to ASCII A-labels. The page accepts at most 1,024 input characters before validation; the resulting domain may be at most 253 characters and each label at most 63. The parser refuses IP addresses, port numbers, underscores, empty labels, single-label names, all-numeric final labels, labels that start or end with a hyphen, and symbols outside letters, digits and hyphens. Each refusal names the specific problem. ### Pasted addresses and email addresses Pasting `https://example.com/path`, `person@example.com`, `mailto:person@example.com`, or the same text inside quotes or angle brackets keeps `example.com`. The drop hint names what was kept. Typing is never rewritten while a word is being entered. Text with no usable domain stays unchanged so the validator can explain it. Pasting anywhere outside another field replaces the source. Dropping or opening a small text file reads it locally, then applies the same cleanup. The file itself is never uploaded. ### When the lookup runs The live lookup runs after typing pauses for 700 milliseconds, on Enter, on leaving the field, after a file or page-wide paste, and when Refresh lookup is pressed. A newer edit aborts the previous request and increments a generation counter, so a slow older answer cannot repaint a newer or cleared input. ### Reserved synthetic input Entering `harbor-supply.example` uses a fixed local mail-routing fixture instead of sending DNS requests. It contains one synthetic MX route and an unknown provider. This exception is for the documented reserved example only; other domains use the live server path. The checked line labels the synthetic run, and its records cannot demonstrate real delivery or provider ownership. ## Reading the result ### Verdict, privacy and findings The verdict names the routing classification. Its chips summarise the mail-route state and any recognised inbound service. The two privacy items distinguish browser work from the one server lookup. Findings repeat the deciding evidence with its consequence, worst first; multiple passing findings fold into one disclosure. A failure is not always a broken domain. Null MX and NXDOMAIN are decisive negative results. Resolver failure and malformed MX are inconclusive because the tool cannot establish a trustworthy route. ### Provider hint and DNS evidence The provider block is supporting evidence, not the routing decision. It compares valid MX names with a bounded signature catalog and can label a mailbox service, gateway, mixed set or unknown route. Gateways can conceal the final mailbox host. DNS evidence lists MX records by preference then hostname, or A and AAAA records when fallback applies. TTL is shown in seconds. The checked line names the canonical domain, observation time and public-DNS path. History follows all current-result evidence; Take it further follows History. ## Method ### Resolve MX first The server validates the domain again, then queries the public resolver for MX. [RFC 5321 section 5](https://www.rfc-editor.org/rfc/rfc5321#section-5) says the lookup “first performs a DNS lookup for an MX record.” The tool follows that order: A and AAAA are never requested when usable MX records exist. The resolver follows only CNAMEs owned by the queried name. It refuses a loop, more than eight alias hops, multiple aliases at one owner, or an alias beside data of the requested type. Responses are limited to 65,536 JSON bytes, must have a supported status, must not be truncated, and must contain well-shaped answers. ### Parse and order MX records Each record must contain a decimal preference from 0 through 65,535 and one target hostname. The hostname must pass the same domain rules as the source, except that the literal dot is reserved for null MX. One malformed record makes the set inconclusive rather than silently discarding evidence. Valid records are sorted by ascending preference and then hostname. [RFC 5321 section 5.1](https://www.rfc-editor.org/rfc/rfc5321#section-5.1) requires senders to try the lowest-numbered preference first; equal-preference hosts are alternatives, not a guaranteed sequence. ### Apply null MX [RFC 7505 section 3](https://www.rfc-editor.org/rfc/rfc7505#section-3) defines a null MX as one record whose preference is zero and whose exchange is the root label. The normative rule says domains that accept no mail “MUST publish a null MX record.” Tamperbox classifies exactly one `0 .` record as explicit refusal. A root target mixed with ordinary MX records, or published with a nonzero preference, is contradictory and becomes invalid MX. The tool does not reinterpret the other records as a working route. ### Apply address fallback Only a successful, empty MX answer reaches fallback. A and AAAA are requested in parallel. Any returned address makes the status `implicit_mx`, a possible mail route under RFC 5321. It is weaker than MX because the address may belong only to a website and the tool does not connect to SMTP. If both address queries answer with no records, the status is `no_mail`. If neither returns an address and either lookup fails, the status is `dns_error`, not no route. NXDOMAIN at the original MX query is separately classified as a nonexistent public domain. ## Standards and conformance ### RFC 5321 | Section | Rule | Implementation boundary | | --- | --- | --- | | [5](https://www.rfc-editor.org/rfc/rfc5321#section-5) | Resolve mail destinations with MX first and implicit MX only when MX is absent | Implemented with an MX query followed by parallel A and AAAA queries only for an empty answer | | [5.1](https://www.rfc-editor.org/rfc/rfc5321#section-5.1) | Prefer lower MX values and treat equal values as alternatives | Records are sorted for display; no delivery attempt is made | | [4.5.3.2](https://www.rfc-editor.org/rfc/rfc5321#section-4.5.3.2) | Domain and path size limits apply to SMTP | Not tested; this tool validates DNS names, not SMTP commands | The implementation stops before address ordering, socket connection, retries, TLS negotiation, SMTP replies and mailbox policy. It is a DNS observation, not an SMTP client. ### RFC 7505 | Section | Rule | Implementation boundary | | --- | --- | --- | | [3](https://www.rfc-editor.org/rfc/rfc7505#section-3) | Publish exactly `0 .` to state that a domain accepts no mail | Exact single-record form is decisive refusal | | [3](https://www.rfc-editor.org/rfc/rfc7505#section-3) | A null MX domain should not run an SMTP listener | Not probed; the tool reports publication only | | [4](https://www.rfc-editor.org/rfc/rfc7505#section-4) | Null MX prevents unnecessary delivery attempts | Explained as the operational consequence; no sender behaviour is simulated | RFC 7505 is current and updates the implicit-MX practice described by SMTP for domains that intentionally receive no mail. ## Finding reference ### Routing findings | Finding | Severity | Meaning | Fix | | --- | --- | --- | --- | | Mail routing is configured | Pass | At least one valid ordinary MX record is published | Keep the routes intentional and test delivery separately | | Does not accept email | Fail | Exactly one null MX explicitly refuses mail | Remove null MX and publish real MX only if the domain should receive mail | | Possible mail route | Check | No MX exists but A or AAAA permits implicit fallback | Publish explicit MX for a deliberate mail service | | No mail route | Fail | The domain does not exist, or no MX/A/AAAA route exists | Correct delegation or publish the intended route | | Inconclusive | Check | DNS failed, timed out, contradicted itself or contained invalid MX | Correct malformed records or retry after DNS recovers | ### Provider findings | Finding | Severity | Meaning | Fix | | --- | --- | --- | --- | | Likely provider | Pass | Every MX maps to one recognised mailbox service | Confirm against the provider configuration | | Gateway detected | Check | A recognised filtering or forwarding edge hides the mailbox host | Use trusted Received headers to identify later hops | | Mixed routes | Check | More than one service, or recognised and unknown hosts, coexist | Verify migration and backup routes before deleting anything | | Provider unknown | Info | Hostnames match no catalog entry | Leave unresolved; unknown is not proof of self-hosting | ## Guide ### Confirm with DNS tools Run `dig +short MX example.com` or `nslookup -type=mx example.com`. Compare every preference and target with the DNS evidence table. For fallback, confirm the absence of MX before running `dig +short A example.com` and `dig +short AAAA example.com`. After a DNS edit, wait at least the previous TTL before treating a repeated observation as global. Recursive caches may retain old answers until that value expires. ### Repair common states | Break it case | What happens | Repair | | --- | --- | --- | | Email address or URL | Shared cleanup keeps the domain | Use the cleaned value or enter only the domain | | Capitals and final dot | Canonical domain is lower-case without the final dot | No DNS edit required | | IP address | Refused before any request | Enter the owning domain, not an address | | Underscore owner | Refused as a mail domain | Use the domain that receives mail, not a DNS record owner | | Single label | Refused without a top-level domain | Enter the complete public name | History records Break it and Heal it replacements. Revert walks changes backward; Reset input returns to the value that began the history. ### Investigate a false expectation If DNS shows a route but mail still fails, test the MX target from an authorised mail environment, inspect SMTP replies and check sender authentication. If the domain uses a gateway, trace a delivered message's Received headers to see downstream hops. Do not use recipient verification against third-party servers as a mailbox-existence test; it is unreliable and can be abusive. ## Worked example The live default is `tamperbox.dev`. In the comparison made on 21 October 2026 it populated three MX rows, identified Cloudflare Email Routing as a gateway and explained that the downstream mailbox host remained unknown. `github.com` and `microsoft.com` each produced one straightforward Microsoft 365 route. Those values are observations, not durable claims. The page runs the real lookup on each load, so hostnames, priorities, TTLs and provider inference can change. The reason for the default is the richer structure: several priorities plus the important difference between an inbound gateway and a mailbox service. ## For agents Agents can run the same live check through the Tamperbox MCP operation `email_domain`, or interpret pasted MX evidence with the bounded analysis operation. Preserve the evidence contract: report publication, observation time and limitations; never convert a routing pass into “mailbox exists” or “delivery works.” When automating, treat `dns_error` and `invalid_mx` as inconclusive, not negative. Keep `null_mx`, `nxdomain` and `no_mail` distinct. Cite the MX targets and preferences behind a conclusion, and carry provider attribution as a separate inference. ## Limits The resolver is one public vantage point with cache state at one moment. Split-horizon and private DNS are invisible. DNSSEC validation is not reported. MX targets are not resolved, SMTP is not contacted, TLS is not negotiated, and address fallback does not establish that port 25 is open. Provider signatures are a maintained catalog rather than an Internet standard. Custom hostnames, resellers, hybrid deployments and gateways can conceal ownership. The tool stores neither input nor report, but the domain is necessarily sent to the server and public resolver to perform a live lookup. ## References - [RFC 5321](https://www.rfc-editor.org/rfc/rfc5321), Simple Mail Transfer Protocol, especially [section 5](https://www.rfc-editor.org/rfc/rfc5321#section-5) and [section 5.1](https://www.rfc-editor.org/rfc/rfc5321#section-5.1). Current Internet Standard, updated by later SMTP extensions that do not replace these routing rules. - [RFC 7505](https://www.rfc-editor.org/rfc/rfc7505), A Null MX Resource Record for Domains That Accept No Mail, especially [section 3](https://www.rfc-editor.org/rfc/rfc7505#section-3). Current Proposed Standard. --- # My Connection Info How My Connection Info reads the TLS version, cipher, HTTP version, round trip, edge location and network of your browser's connection, how each layer is graded, and what to change when one is out of date. Canonical: https://docs.tamperbox.dev/tools/connection-info/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A browser on the connection to describe Outputs: The path from the device to the edge, each layer (TLS, cipher, HTTP, round trip) graded, the edge location and network, and findings for deprecated TLS, older ciphers, high latency and HTTP/3 Limitations: Describes one connection to one site's edge; a VPN or proxy negotiates its own settings; the round trip is to the nearest edge only The tool page is [tamperbox.dev/connection-info](https://tamperbox.dev/connection-info). Like What Is My IP, it has no input box: opening it reads how this browser connected to our edge and grades each layer. This page is the long version: where each value comes from, the rule behind every grade, and what usually causes an old TLS version, an older cipher, HTTP/1.1 or a high round trip. <div class="tb-callout"><strong>Where processing happens:</strong> opening the page sends one request to the Tamperbox server. Cloudflare's edge, which terminates the connection, attaches its measurements to that request; the server returns only the allowlisted values. The browser renders and grades the returned fields. This check performs no general device or network scan.</div> ## What the tool answers 1. **How is this connection protected?** The TLS version and the cipher suite negotiated. 2. **Which HTTP version is in use?** HTTP/1.1, HTTP/2 or HTTP/3. 3. **How far away is the edge?** The round-trip time measured by the edge, and which location answered. 4. **Through which network?** The address, AS number, network name and estimated country. ## Inputs There is nothing to type. Check again reads the connection again, which is how you compare a browser, a VPN or a network with another: open the page there and check. ## Reading the result ### Verdict and chips The verdict names the TLS and HTTP versions, for example "TLS 1.3 over HTTP/2", then the round trip and the edge location. Its tone is the worst graded layer. One chip per graded layer gives its word: Current, Secure, Deprecated; Modern, Older; HTTP/3, Multiplexed, One at a time; Fast, Typical, High. ### Findings Every layer graded CHECK or FAIL, then the HTTP/3 note and the scope note; see the [Finding reference](#finding-reference). ### From this device to our server Three steps: this device (address, network, AS number, country), the link (round trip, labelled TCP or QUIC), and our edge (its airport code and city). ### Each layer Every layer with its value, grade and what it means, then the edge location, network and address as reported values. ### Take it further These links carry values derived from the current result. A link is absent when its required evidence is missing; the tool does not invent a target. | Destination | Value and condition | | --- | --- | | [ASN Lookup](https://docs.tamperbox.dev/tools/asn-lookup/) | The address reported for this connection | | [BGP Route Lookup](https://docs.tamperbox.dev/tools/bgp-lookup/) | The same observed address | | [Reverse DNS](https://docs.tamperbox.dev/tools/reverse-dns/) | The same observed address | Check the rest opens sibling pages without carrying the address. Take it further is the explicit address transfer. These pages have no editable source, Break it, Heal it or input History; Check again refreshes the connection reading. ### What this result means Six cards explain the current findings: Ask your agent, In plain words, What does it mean?, What good looks like, How to fix it, and Tool limitations. Expand a card to read the explanation and its method or guide link. Copying an agent prompt does not run another check. The cards interpret the evidence already shown; they are not an additional measurement or an independent confirmation. If the connection reading fails or no result is available, result-specific cards clear and contextual links disappear. Read the verdict before relying on a card, and distinguish a missing observation from a confirmed negative result. ## Method ### 1. Where the values come from Cloudflare's edge terminates TLS and HTTP for the site and records what it negotiated in the request's `cf` object. The server copies only these fields, with text values limited to 256 characters and numeric values retained only when finite and non-negative: `tlsVersion`, `tlsCipher`, `httpProtocol`, `clientTcpRtt` or `clientQuicRtt`, `colo`, `asn`, `asOrganization` and `country`. The address comes from `CF-Connecting-IP` (or `CF-Connecting-IPv6` when the edge replaced an IPv6 address with a pseudo IPv4 one). Missing values stay empty; they are never guessed. For HTTP/3 the TCP round trip is not reported and the QUIC one is used. ### 2. Grading TLS | Value | Grade | Rule | | --- | --- | --- | | TLS 1.3 | PASS, Current | [RFC 8446](https://www.rfc-editor.org/rfc/rfc8446#section-1.2): only AEAD ciphers, one round trip fewer to set up | | TLS 1.2 | PASS, Secure | Still secure with a modern cipher; something may be holding the browser back from 1.3 | | TLS 1.0, 1.1 | FAIL, Deprecated | [RFC 8996, section 4](https://www.rfc-editor.org/rfc/rfc8996#section-4): "TLS 1.0 MUST NOT be used"; [section 5](https://www.rfc-editor.org/rfc/rfc8996#section-5) says the same for 1.1 | | Not reported | INFO, Unknown | Says nothing about whether the connection is encrypted | ### 3. Grading the cipher | Cipher | Grade | Rule | | --- | --- | --- | | Name contains GCM, CHACHA20, POLY1305 or CCM | PASS, Modern | Authenticated encryption ([RFC 5116](https://www.rfc-editor.org/rfc/rfc5116#section-1)), the only kind TLS 1.3 allows | | Name contains CBC, or ends in SHA | CHECK, Older | CBC-mode suites kept for old clients; [RFC 9113, section 9.2.2](https://www.rfc-editor.org/rfc/rfc9113#section-9.2.2) forbids many of them for HTTP/2 | | Anything else | INFO, Reported | Shown as negotiated | ### 4. Grading HTTP | Protocol | Grade | Meaning | | --- | --- | --- | | HTTP/3 | PASS | Over QUIC on UDP ([RFC 9114](https://www.rfc-editor.org/rfc/rfc9114#section-3.1)): avoids TCP head-of-line blocking between streams and can support connection migration | | HTTP/2 | PASS, Multiplexed | Many requests share one TCP connection ([RFC 9113, section 5](https://www.rfc-editor.org/rfc/rfc9113#section-5)) | | HTTP/1.1 | INFO, One at a time | Often forced by a proxy, an extension or an old client | A browser learns that a site offers HTTP/3 from the `Alt-Svc` header ([RFC 7838, section 3](https://www.rfc-editor.org/rfc/rfc7838#section-3); [RFC 9114, section 3.1.1](https://www.rfc-editor.org/rfc/rfc9114#section-3.1.1)) and usually switches on a later connection. So an HTTP/2 first visit adds the informational finding "HTTP/3 was not used": check again, and if it never switches, UDP 443 may be blocked on the network. ### 5. Grading the round trip Under 50 ms is Fast and under 150 ms Typical, both PASS; 150 ms or more is High, CHECK. The edge measures the round trip itself, between it and your device, so the number includes your Wi-Fi and every network in between, but not the server behind the edge. ### Reading a cipher suite name The cipher is shown as the edge names it, which follows OpenSSL's style rather than the IANA registry names. Two real-shaped values, part by part: | Part of `AEAD-AES128-GCM-SHA256` (TLS 1.3) | Meaning | Grade input | | --- | --- | --- | | `AEAD` | The record protection is authenticated encryption; TLS 1.3 suites name only this part, because key exchange and authentication are negotiated separately ([RFC 8446, section 1.2](https://www.rfc-editor.org/rfc/rfc8446#section-1.2)) | | | `AES128` | AES with a 128-bit key | | | `GCM` | Galois/Counter Mode, an AEAD mode | Matches GCM: Modern | | `SHA256` | The hash used by the key schedule, not a MAC on records | | | Part of `ECDHE-RSA-AES128-SHA` (TLS 1.2) | Meaning | Grade input | | --- | --- | --- | | `ECDHE` | Ephemeral elliptic-curve Diffie-Hellman key exchange: forward secrecy | | | `RSA` | The server authenticates with an RSA certificate | | | `AES128` | AES with a 128-bit key, in CBC mode (implied when no mode is named) | | | `SHA` | HMAC-SHA1 protects each record, MAC-then-encrypt | Ends in SHA: Older | The second suite still has forward secrecy, which is why it is graded CHECK, not FAIL. Its weakness is the CBC construction, the source of padding-oracle attacks such as Lucky Thirteen; AEAD suites avoid that class entirely. ### What changes a reading - **A VPN** carries your traffic to its exit, and the edge measures the connection from that exit: the address, network, country and edge location are the VPN's, and the round trip includes the tunnel. - **A private relay** in some browsers sends traffic through two hops; the edge sees the second hop's address and a network belonging to the relay operator. - **HTTPS inspection** by antivirus or a company proxy ends your browser's TLS on your machine or network and opens a new connection with the product's own TLS version and cipher, which is what this page then shows. - **The network itself**: some networks block UDP, which keeps every connection on HTTP/2, and congested Wi-Fi raises the round trip without changing anything else. ### 6. Edge location The `colo` code is the nearest airport to the location that answered. Common codes are named (AMS is Amsterdam, IAD is Ashburn, NRT is Tokyo); others are shown as reported. Your provider's routing, not distance alone, decides which location answers. <span id="standards"></span> ## Standards and conformance | Specification | Sections used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 8446](https://www.rfc-editor.org/rfc/rfc8446) TLS 1.3 | [1.2](https://www.rfc-editor.org/rfc/rfc8446#section-1.2) | TLS 1.3 graded Current | Key exchange group and certificate are not shown; see the SSL Certificate Checker | | [RFC 8996](https://www.rfc-editor.org/rfc/rfc8996) | [4](https://www.rfc-editor.org/rfc/rfc8996#section-4), [5](https://www.rfc-editor.org/rfc/rfc8996#section-5) | TLS 1.0 and 1.1 graded Deprecated | | | [RFC 5116](https://www.rfc-editor.org/rfc/rfc5116) AEAD | [1](https://www.rfc-editor.org/rfc/rfc5116#section-1) | AEAD suites graded Modern by name | The grade reads the suite name; it does not test the cipher | | [RFC 9113](https://www.rfc-editor.org/rfc/rfc9113) HTTP/2 | [5](https://www.rfc-editor.org/rfc/rfc9113#section-5), [9.2.2](https://www.rfc-editor.org/rfc/rfc9113#section-9.2.2) | HTTP/2 graded Multiplexed; CBC suites flagged | | | [RFC 9114](https://www.rfc-editor.org/rfc/rfc9114) HTTP/3 | [3.1](https://www.rfc-editor.org/rfc/rfc9114#section-3.1), [3.1.1](https://www.rfc-editor.org/rfc/rfc9114#section-3.1.1) | HTTP/3 detected from the edge's protocol value | Does not test UDP reachability itself | | [RFC 7838](https://www.rfc-editor.org/rfc/rfc7838) Alt-Svc | [3](https://www.rfc-editor.org/rfc/rfc7838#section-3) | Explains why HTTP/3 appears on a later visit | | ## Finding reference | Finding | Severity | What it means for your browsing | Fix | | --- | --- | --- | --- | | TLS: TLS 1.0 or 1.1 | FAIL | Most sites refuse the connection | Update the browser and OS; check HTTPS-inspecting software | | Cipher: a CBC suite | CHECK | Older protection chosen, often by a proxy | Update the browser; check the proxy | | Round trip: 150 ms or more | CHECK | Pages and calls feel slow | Try without VPN; use a cable; compare networks | | HTTP/3 was not used | INFO | Normal on a first visit; persistent means UDP 443 may be blocked | Check again; ask the network admin about UDP 443 | | Only this connection is described | INFO | Other sites, VPNs and proxies negotiate their own | | ## Guide ### Old TLS or an older cipher Update the browser and the operating system first. If they are current, something between the browser and the internet is choosing for it: antivirus with "HTTPS scanning", a company proxy, or a parental-control filter. These intercept TLS and open their own connection with their own settings. Ask the administrator to check or update the inspection software, then repeat the observation under the approved configuration. ### Stuck on HTTP/1.1 Browser extensions that rewrite traffic, corporate proxies and some security products downgrade to HTTP/1.1. Try a private window without extensions, then another network. ### High round trip Turn off any VPN and check again; compare Wi-Fi with a cable, and with mobile data. A high number on every network points at the device or a distant edge; a high number on one network points at that network. ### Confirm without Tamperbox ```sh curl -sI --http2 -o /dev/null -w '%{http_version}\n' https://tamperbox.dev/ openssl s_client -connect tamperbox.dev:443 -brief </dev/null ``` The first prints the HTTP version curl negotiated, the second the TLS version and cipher. They describe curl's connection, which may differ from the browser's. ## Worked example A current browser on a home connection typically reads "TLS 1.3 over HTTP/2", a round trip of a few tens of milliseconds, and an edge in the nearest large city. TLS is Current, the cipher (for example `AEAD-AES128-GCM-SHA256`) is Modern, HTTP/2 is Multiplexed, and the informational finding notes that HTTP/3 was not used. Checking again often switches to HTTP/3, with the round trip now labelled QUIC. With a VPN on, the edge location and network change to the VPN's exit. This page never shows a sample connection, so there is no fixed example to describe. ## For agents Through the Tamperbox MCP server, `connection_info` describes the connection of whatever calls it: the agent's server or HTTP client, not the person using the agent, and the result carries that warning. Use it to inspect the caller context reported by the service; a proxy or gateway may be the visible peer. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Security and privacy](https://docs.tamperbox.dev/reference/security/). [What Is My IP](https://docs.tamperbox.dev/tools/what-is-my-ip/) shows the address and tests both IP families from the device. ### Transfers to another tool Explicit sibling-tool controls can carry the current input or observed address to another page. The shared navigation stores that value temporarily in tab-scoped `sessionStorage`, accepts a transfer for at most one minute, and puts a random transfer token in the URL fragment. The input itself is not placed in the URL. The receiving page consumes the transfer and applies its own input rules; tools with a manual Run button still require that action for live checks. This is not a saved result, and the destination can send the value to the services it needs. Ordinary edits and lookups do not create a durable report archive. ## Limits - One connection to one site's edge. - A VPN, proxy or HTTPS-inspecting product negotiates its own settings. - The round trip is to the answering edge, not to every server. - Values the edge does not report stay empty. - The page keeps results in memory. Explicit transfers to another tool use temporary session storage. ## References - [RFC 8446](https://www.rfc-editor.org/rfc/rfc8446), The Transport Layer Security (TLS) Protocol Version 1.3: section 1.2. - [RFC 8996](https://www.rfc-editor.org/rfc/rfc8996), Deprecating TLS 1.0 and TLS 1.1: sections 4 and 5. - [RFC 5116](https://www.rfc-editor.org/rfc/rfc5116), An Interface and Algorithms for Authenticated Encryption: section 1. - [RFC 9113](https://www.rfc-editor.org/rfc/rfc9113), HTTP/2: sections 5 and 9.2.2. - [RFC 9114](https://www.rfc-editor.org/rfc/rfc9114), HTTP/3: sections 3.1 and 3.1.1. - [RFC 7838](https://www.rfc-editor.org/rfc/rfc7838), HTTP Alternative Services: section 3. --- # Naughty Strings List What is in the Naughty Strings List, how its eleven groups and active payloads are chosen, how search and export work, and how to use the strings in manual and automated tests. Canonical: https://docs.tamperbox.dev/tools/naughty-strings/ Updated: 2026-10-25 Applies to: tamperbox.dev, October 2026 Prerequisites: A field, API, import or file name you are allowed to test Outputs: A filtered list of strings with reasons, character and byte counts, and an export in the format your tests use Limitations: A starting set, not a complete security test; active payloads are for systems you may test; nothing is sent anywhere The tool page is [tamperbox.dev/naughty-strings](https://tamperbox.dev/naughty-strings). It opens on every data-only string, with active payloads hidden. <div class="tb-callout"><strong>Where processing happens:</strong> the list is part of the page. Searching, filtering, copying and downloading happen in your browser, and no server request is made.</div> ## What the tool answers Which values should I type into this field, send to this API or put in this file to find out whether it handles real input? Each string carries one sentence on what it tests, so a failure points at a cause. ## The groups | Group | What it tests | |---|---| | Empty and punctuation | Empty values, lone quotes, backslashes, entities and brackets | | Whitespace | Spaces, tabs, line breaks, no-break and full-width spaces | | Invisible and tricky Unicode | Zero width characters, direction overrides, look-alike letters, decomposed accents, emoji sequences, lone surrogates, case mapping that changes length | | Encoding damage | Mojibake, entities and percent-encoding in plain fields | | Real names that break rules | Apostrophes, the surname Null, one-word names, long names, CJK and Vietnamese names | | Numbers and keywords as text | Integer limits, floating point, NaN and Infinity, locale separators, other digit scripts, null and undefined written as text | | Dates and times | Leap days, the zero date, 2038, leap seconds, ambiguous slash dates, a time skipped by daylight saving | | Emails, URLs and identifiers | Valid addresses that validators refuse, IPv6 and Unicode hosts, nil UUIDs, short IPv4 forms | | Spreadsheet formulas | Cells starting with =, +, - or @ that run when a CSV is opened (active) | | Injection | SQL, NoSQL, LDAP, HTML and script, template, format string, command, header, XML entity and prototype payloads (active) | | Paths and reserved names | Traversal and file URLs (active), Windows reserved names, trailing dots, long and Unicode file names | ## Active payloads A string is marked active when it is built to be acted on if it reaches a parser, interpreter, spreadsheet or file system. They are hidden by default so that a copied list is safe to paste into a shared staging system. None is malware and none needs a network; command payloads only sleep for five seconds. Include them only for systems you own or are allowed to test. ## Searching and export Search matches the string's name, its reason, its group and its value written with code point tags, so `U+200B` finds the zero width space. Export formats: - **JSON, JavaScript and Python:** an array or list literal with every invisible character written as an escape, ready for a parameterised test. - **CSV:** one value per row under a `value` header, quoted where needed. - **One per line:** raw values; values that hold a line break span two lines, so prefer JSON or CSV for those. ## Reading a result A value that is stored and shown back exactly as sent has passed. A refusal with a clear message is fine where the value is truly invalid. Anything else, such as a changed value, a server error, a value run as code or a value that breaks the page around it, is a finding. ## Method 1. The list is a fixed set of 158 strings, each with an identifier, a group, a reason and a flag for active payloads. 2. A string is active when it is built to be acted on by a parser, interpreter, spreadsheet or file system. Active strings are excluded until included. 3. Search lowercases the query and matches it against the identifier, the reason, the group and the value with invisible characters written as code point tags. 4. Exports write each value as a string literal for the chosen language. In JSON, JavaScript and Python every invisible or unprintable character is an escape; CSV quotes values with commas, quotes, line breaks or edge spaces. ## Finding reference | Result after submitting a string | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | Stored and shown back unchanged | pass | | The value was handled as data | None | | Refused with a clear message | pass | | Validation caught a truly invalid value | Check the rule does not refuse real names or addresses | | Shown back changed (trimmed, cut, decoded) | check | [OWASP WSTG](https://owasp.org/www-project-web-security-testing-guide/) | Data is lost or altered on the way | Store exactly what was sent, validate explicitly | | Server error | fail | [OWASP WSTG](https://owasp.org/www-project-web-security-testing-guide/) | An unhandled case, often a query or encoding bug | Use parameterised queries and UTF-8 throughout | | Value run as code or markup | fail | [OWASP WSTG](https://owasp.org/www-project-web-security-testing-guide/) | Injection | Encode output for its context; never build code from input | | Formula runs when an export is opened | fail | [OWASP: CSV Injection](https://owasp.org/www-community/attacks/CSV_Injection) | Spreadsheet formula injection | Prefix cells starting with = + - @ with an apostrophe on export | ## Guide ### Test a form field by hand 1. Search or tick the groups that matter for the field (names, emails, dates). 2. Copy each string, submit it, then read the stored value back from the page and from an export. 3. Record anything that is not "stored and shown back unchanged" or "refused with a clear message". ### Feed a parameterised test Choose JSON, JavaScript or Python, Copy all or Download, and use the list as test parameters. Invisible characters arrive as escapes, so the test file stays readable. ### Test exports Include active payloads, tick Spreadsheet formulas, put the strings into records, export to CSV and open the file in a spreadsheet. Any cell that calculates is a finding. ## Use it from an agent The `naughty_strings` operation takes a search as its input text and returns the matching strings with their reasons. Set `category` to limit the group and `includeActive` to include active payloads. See the [MCP documentation](https://docs.tamperbox.dev/mcp/). ## References - [OWASP Web Security Testing Guide](https://owasp.org/www-project-web-security-testing-guide/) - [OWASP: CSV Injection](https://owasp.org/www-community/attacks/CSV_Injection) - [Unicode Technical Standard #39: Unicode Security Mechanisms](https://www.unicode.org/reports/tr39/) - [Microsoft: Naming files, paths, and namespaces](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file) --- # NS Lookup How the NS Lookup reads the nameservers a zone delegates to, names the provider behind each one, checks redundancy and mixed providers, and how to finish a DNS migration or add redundancy and confirm it. Canonical: https://docs.tamperbox.dev/tools/ns-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A zone apex such as example.com, or NS records to paste Outputs: A verdict naming how many nameservers and which providers, findings, one row per nameserver with its provider, and the answer as dig-style text Limitations: These are the NS records the zone publishes as one resolver returns them; the parent's delegation can differ, and the nameservers are not asked whether they answer The tool page is [tamperbox.dev/ns-lookup](https://tamperbox.dev/ns-lookup). It opens on `harbor-supply.example`, a sample domain on the reserved `.example` zone served by two providers, as after a DNS migration that was never finished. This page is the long version: what the NS records say, how providers are named, the rules applied, and how to finish a migration safely. <div class="tb-callout"><strong>Where processing happens:</strong> a name is sent to the Tamperbox server, which asks Cloudflare for its NS records over DNS over HTTPS. Pasted records are read in your browser and never uploaded. Sample names under <code>.example</code> are answered in the browser. Ordinary lookup results are not persisted by this page. An explicit handoff temporarily stores its value in session storage for one-use transfer.</div> ## What the tool answers A zone's NS records name the servers that hold its records ([RFC 1035 section 3.3.11](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.11)): an NS record gives "a host which should be authoritative for the specified class and domain". Every name in the zone, from the website to the mail servers, is answered by these servers. The tool answers: 1. **Which servers serve this zone?** The NS records, by host name. 2. **Who runs them?** The DNS provider behind each host, or "Self-hosted" when the servers live inside the zone itself. 3. **Is there redundancy?** One nameserver is a single point of failure. 4. **Is more than one provider listed?** Deliberate for some large sites; after a move, usually an unfinished migration. It does not ask each nameserver whether it answers, does not compare the zone's own NS records with the delegation the parent zone publishes (the registry's side, which WHOIS shows), and does not check glue addresses. ## Inputs ### A name `example.com`. NS records sit at a zone's apex, so a name inside a zone (`mail.example.com`) has none of its own: the page says so and offers, in Heal it, to look up the zone that holds it, read from the authority section of the answer. The lookup runs when you stop typing, or on Enter. A pasted address or email address is reduced to its host or domain. ### Pasted records Anything with a space or a quote is read as records, in the browser: dig answers, zone file lines, or one nameserver host per line. Providers are named the same way; nothing is looked up. ### Files Drop a `.txt` file anywhere on the page. ## Reading the result ### Verdict and chips "3 nameservers at Cloudflare and Amazon Route 53." The chips name each provider, marked as a check when there is more than one. ### Where your input goes Pasted records stay in the browser; a name means one NS query from our server. ### Findings Failures, checks and notes first, the passes folded. ### NS records One row per nameserver: the host and its provider, "Self-hosted", or "Not in the catalog" with the domain the host belongs to. ### DNS response The answer as dig-style text, with a copy button. ### History and Heal it History logs every Break it and Heal it change. Heal it offers "Look up" followed by the zone's name when the name is inside a zone. ### Take it further The zone to the DNSSEC Checker, the zone to the WHOIS Lookup (the delegation at the registry), and for a live zone the first nameserver to the DNS Lookup for its addresses. ## Method ### 1. The question The server asks Cloudflare for the NS records at the name. At a zone apex the answer holds them. Below the apex the answer is empty (NODATA) and the authority section names the zone's SOA, which gives the zone's name for the Heal it repair. ### 2. Naming the provider Each host is compared with a catalog of 29 providers' nameserver patterns: Cloudflare (`*.ns.cloudflare.com`), Amazon Route 53 (`ns-N.awsdns-N.com` and its `.net`, `.org`, `.co.uk` siblings), Google Cloud DNS, Azure DNS, GoDaddy, Namecheap, NS1, DNSimple, DigitalOcean, Akamai Edge DNS, UltraDNS, Oracle Dyn, Hetzner, OVHcloud, Gandi, Porkbun, Vercel, Wix, Squarespace, Hostinger, Network Solutions, Hurricane Electric, Linode, Name.com, IONOS, Bluehost, Hover, Gcore and deSEC. A host that matches none and lives inside the zone being looked up is "Self-hosted". Anything else is named by the last two labels of its host name, "Not in the catalog (example.net)". A provider that runs its nameservers under a customer's own domain (vanity nameservers) appears as self-hosted. ### 3. Rule: at least two nameservers One NS record: fail, "Only one nameserver". [RFC 1034 section 4.1](https://www.rfc-editor.org/rfc/rfc1034#section-4.1): "By administrative fiat, we require every zone to be available on at least two servers." [RFC 2182 section 5](https://www.rfc-editor.org/rfc/rfc2182#section-5) goes further: "It is recommended that three servers be provided for most organisation level zones, with at least one which must be well removed from the others." Two or more: pass, "N nameservers". The count says nothing about whether the servers are on separate networks; two names for one machine pass. ### 4. Check: more than one provider Two or more distinct providers: check, "N providers answer for this zone". Some operators run two providers on purpose, so this is not a failure. The risk is that the providers serve different records: a resolver spreads its questions across every listed nameserver, so visitors get whichever copy it happened to ask. After a migration, the old provider's servers left in the list are the usual cause, and they go on serving the old zone for as long as the delegation points at them. ### 5. Notes - **Self-hosted nameservers** (info): the zone's servers are named inside the zone, so the parent must publish glue addresses for them, and those must match the servers' real addresses. - **N nameservers not in the catalog** (info): the provider is shown by the domain of the host name. ### 6. Verdict "N nameservers at providers", as fail when any failure applies, check when a check applies, otherwise pass. ## Standards and conformance | Specification | Sections used | How the tool applies it | Where it stops | | --- | --- | --- | --- | | [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034) | [4.1](https://www.rfc-editor.org/rfc/rfc1034#section-4.1), [4.2.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.2.2) | A single nameserver fails; redundancy is the reason | Network separation of the servers is not checked | | [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035) | [3.3.11](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.11) | NS data is read as host names | Additional-section addresses are not shown | | [RFC 2182](https://www.rfc-editor.org/rfc/rfc2182) | [5](https://www.rfc-editor.org/rfc/rfc2182#section-5) | Quoted as the recommendation of three; the tool passes two | The tool does not warn at two | | [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308) | [2.2](https://www.rfc-editor.org/rfc/rfc2308#section-2.2) | A name inside a zone gets NODATA with the zone's SOA, which names the zone | | The zone's own NS records and the parent's delegation are supposed to match, but the tool reads only one side. [RFC 1034 section 4.2.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.2.2) asks new zone owners to "demonstrate redundant name server support" before delegation; nothing in the protocol enforces it afterwards. ## Finding reference | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | N nameservers | pass | [RFC 1034 4.1](https://www.rfc-editor.org/rfc/rfc1034#section-4.1) | Enough servers to survive one failing | None | | Only one nameserver | fail | [RFC 1034 4.1](https://www.rfc-editor.org/rfc/rfc1034#section-4.1) | If it is unreachable, every name in the zone stops resolving | Add the other nameservers your provider assigns, at the registrar and in the zone | | N providers answer for this zone | check | [RFC 1034 4.1](https://www.rfc-editor.org/rfc/rfc1034#section-4.1) | Visitors may get different answers from different providers | Remove the old provider, or keep both in step | | Self-hosted nameservers | info | [RFC 1034 4.2.1](https://www.rfc-editor.org/rfc/rfc1034#section-4.2.1) | Glue at the parent must match the servers' addresses | Check the glue at your registrar | | N nameservers not in the catalog | info | | The provider is named by the host's domain | None | | No NS record at name | info | [RFC 2308 2.2](https://www.rfc-editor.org/rfc/rfc2308#section-2.2) | The name is inside a zone | Look up the zone (Heal it) | | The name does not exist | fail | [RFC 2308 2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1) | No zone or name here | Check the spelling | | The resolver could not answer | fail | [RFC 1035 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) | Validating resolvers return nothing | Check the DNSSEC chain | ## Guide ### Finish a DNS migration 1. Make sure the new provider holds every record: compare a few names (the apex A record, `www`, MX, the TXT records) on both providers' servers. `dig @<old nameserver> example.com MX` and `dig @<new nameserver> example.com MX` should match. 2. At your registrar, set the nameservers to the new provider's only. 3. In the zone at the new provider, make the NS records at the apex list the same servers. 4. Wait at least the TTL of the old NS records (often one or two days), then cancel the old zone. 5. Look the zone up here: one provider, no check. Confirm from a terminal: `dig +short NS example.com` lists the zone's view; `dig +norecurse @a.gtld-servers.net example.com NS` (for `.com`; use your TLD's servers) shows the parent's delegation. Both should list the same hosts. ### Add redundancy Use every nameserver your provider assigns (Cloudflare gives two, Route 53 four, Azure four). Add them at the registrar and in the zone. For a zone whose outage would be costly, a second provider kept in step by zone transfers or by an API is the step after that. ### Self-hosted nameservers When `ns1.example.com` serves `example.com`, the registrar must publish glue: the addresses of `ns1.example.com` in the parent zone. After changing those servers' addresses, update the glue at the registrar, or resolvers keep going to the old addresses. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | A subdomain | `mail.harbor-supply.example` | No NS records of its own, and Heal it looking up the zone | | One nameserver | your first NS record, pasted alone | "Only one nameserver" | | Name does not exist | `nohost.` in front of your name | NXDOMAIN | ## Worked example `harbor-supply.example` lists three nameservers: two Cloudflare hosts and one Route 53 host. The verdict reads "3 nameservers at Cloudflare and Amazon Route 53.", with a check chip on each provider. Findings carries the check "2 providers answer for this zone" and the pass "3 nameservers". The synthetic example models a possible unfinished migration. Multiple providers can also be intentional; their names alone do not prove a migration mistake. Until it is, some resolvers ask Route 53, which may still serve last month's records. The cards walk through finishing the migration, and Take it further offers the zone to the DNSSEC Checker and to the WHOIS Lookup, where the registry's delegation shows which list resolvers start from. ## For agents The Tamperbox MCP server exposes `ns_lookup` with a `name`, returning an `evidence` object with the question, status, flags, answer and authority, plus `records` for the requested type. Provider naming is a separate operation, `dns_provider`, which reads the nameservers and names providers without guessing unknown ones. Keep these warnings with any conclusion: - An NS record does not prove the server answers or holds the right records. - The zone's NS records and the parent's delegation can differ. - One answer from one resolver at one moment. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/). ## Limits - The zone's NS records only; not the parent's delegation, not glue, not each server's answers. - Providers are named from host name patterns; vanity nameservers look self-hosted. - Network separation of the servers is not tested. - Pasted records are read as text. - Sample names under `.example` are answered in the browser. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034): sections 4.1 (at least two servers), 4.2.1 (zone top and glue), 4.2.2 (delegation). - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035): section 3.3.11, NS RDATA; section 4.1.1, response codes. - [RFC 2182](https://www.rfc-editor.org/rfc/rfc2182): selection and operation of secondary DNS servers. Section 5, how many. - [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308): sections 2.1 and 2.2. --- # Open Graph Preview How the Open Graph preview reads a page's share tags, the fallback order each platform's card follows, every rule it applies to the image, title, description and X card, and how to fix each finding. Canonical: https://docs.tamperbox.dev/tools/open-graph-preview/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public page address, or the page's HTML to paste Outputs: A verdict, findings, four approximate previews, the tags to add and every share-related tag found with the previews that use it Limitations: Previews approximate each platform's card; platforms cache cards; tags added by scripts are not seen; live images stop at 5 MiB The tool page is [tamperbox.dev/open-graph-preview](https://tamperbox.dev/open-graph-preview). It checks `tamperbox.dev` live when opened, says whether the link is ready to share, and draws the cards platforms make from it. This page is the long version: where each card gets its text and image, every rule, what each finding means, and how to fix it. <div class="tb-callout"><strong>Where processing happens:</strong> pasted HTML is read in your browser. Its share image is fetched only if you press the button that loads it, and then through the Tamperbox server, so your browser never contacts that site. A page address is fetched by the Tamperbox server, with its share image, when you stop typing. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. Sample addresses on the reserved <code>.example</code> zone are answered in the browser from a fixture.</div> ## What the tool answers 1. **Will the shared link have a picture, and a large one?** The image tag, whether the image loads, and its real size decide between a large card, a small thumbnail and no picture. 2. **What title and text will people see?** Each platform's fallback order picks a title and description; the previews show the result, cut where platforms cut. 3. **Does X draw it the same way?** `twitter:card` decides X's layout separately. 4. **What should be added?** The missing tags, written from what the page already says. ## Inputs ### A page address `example.com/blog/post` or `https://example.com/blog/post`. Without a scheme the address starts at `https://`. The page is fetched when you stop typing (about two thirds of a second), or at once on Enter. The same refusals as every site tool apply: spaces, other schemes, credentials (Heal it removes them), ports other than 80 and 443 (Heal it offers the standard port), IP addresses and single-label names. ### Pasted HTML Anything that starts with `<` is read as HTML: a whole page or just its `<head>`. It is read in the browser. A share image on a live site is not fetched until you press **Load the image through our server**; a relative image address cannot be resolved because a pasted page has no address. Files up to 2 MiB can be dropped or opened with **Add a file** (`.html`, `.htm`, `.txt`). A pasted address loses surrounding quotes, angle brackets and trailing punctuation; the whole address is kept, path included, because each page has its own tags. Text that is neither an address nor HTML stays as pasted so the error can explain it. ## Reading the result ### Verdict and chips One of: "Ready to share.", "Shares with a small image.", "Shares without a picture.", "Fix the image address:" or "Sharing metadata needs fixes:", with what costs the card most. The chips count the problems and scroll to the findings. When only platform limitations remain (X's small square, a cut title), one chip counts them. Two items say where the input went: pasted HTML stays in the browser; a page address means our server fetches the page and its image. ### Findings Every finding, worst first; two or more passing findings are grouped under an expandable **checks passed** row. A single passing finding stays visible. ### Previews Four approximate cards: a large card (Facebook, LinkedIn), switching to a small link card when the image is under 600 × 315; an X card in the layout `twitter:card` asks for; a chat unfurl (Slack, Discord, Teams); and a search result. Titles and descriptions are clamped or cut where each surface cuts them. ### Tags to add The missing tags as code to paste inside `<head>`, built only from values the page already has. Copy with the button in the corner. ### Tags found Every Open Graph, Twitter, description, robots and viewport tag, the canonical and icon links and any JSON-LD types, each with the previews that read it. ### History History follows the current result evidence. Break it and Heal it record input changes, newest first. **Revert** restores the input before the latest recorded change; **Reset input** restores the input before the first retained change and clears the list. **Restore input before this break** under Heal it also reverts the latest change. These actions reload and check the restored input. Restoring a public address can therefore send a new request, including on the two tools whose ordinary typing waits for a run button. Editing or pasting a new input clears History. The list lives in the current page; it is not saved monitoring data and does not restore an old network response. ### Take it further Only links with an available result value appear. | Follow-up | Value carried | When offered | | --- | --- | --- | | [Redirect Checker](https://tamperbox.dev/redirect-checker) | Resolved `og:url`, or the canonical URL as fallback | Fetched HTML names either address | | [Website Down Checker](https://tamperbox.dev/website-down-checker) | Share image URL | Fetched HTML names an HTTP(S) image | | [SSL Checker](https://tamperbox.dev/ssl-checker) | Share image host | An HTTPS image failed, or its host differs from the page host | These follow-ups are hidden for pasted HTML, even when its tags contain addresses. ### Related checks and input transfer Check the rest carries the current address to a sibling tool. Take it further carries the specific value listed above. Pasted file contents are not transferred through these links. Transfers temporarily use browser `sessionStorage` with a one-use random token in the URL fragment; the input itself is not in the URL. The destination accepts a transfer for less than one minute and removes the token. Manual destination tools wait for their run button or Enter. Each destination collects new evidence. A follow-up link does not confirm the original verdict or repair the remote site. ### Result cards Six expandable cards below the result explain its meaning, give a beginner explanation, offer an agent prompt, describe good practice, suggest fixes and state limitations. Their text follows the current result; it is not another measurement. Open a card for its full explanation and the relevant [Method](#method) or [Guide](#guide). The agent prompt can be copied for review; copying it does not run a repair or send it to an agent. ## Method ### Reading the tags The HTML is scanned as served: up to 512 KiB when our server fetches the page (following up to 10 redirects, `TamperboxBot/1.0`, no cookies), or the whole pasted source. Scripts do not run. Each `<meta>` is read by its `property`, `name`, `http-equiv` or `itemprop` key, lowercased, with its `content` ([HTML Standard, the meta element](https://html.spec.whatwg.org/multipage/semantics.html#the-meta-element)). The first `<title>`, the first `<base href>`, every `<link rel>` and every JSON-LD block are kept. For each key the first tag with non-empty content wins, which is how the [Open Graph protocol](https://ogp.me/#array) treats repeated properties ("the first tag (from top to bottom) is given preference"). ### The fallback order | Card | Title | Description | Image | Address | | --- | --- | --- | --- | --- | | Large card, chat | og:title, twitter:title, `<title>` | og:description, twitter:description, meta description | og:image, og:image:url, og:image:secure_url, twitter:image, twitter:image:src | og:url, canonical link | | X | twitter:title, og:title, `<title>` | twitter:description, og:description, meta description | twitter:image, twitter:image:src, og:image | | | Search result | `<title>`, og:title | meta description, og:description | | | Relative addresses are resolved against `<base href>` when present, otherwise against the page address ([RFC 3986, section 5.2](https://www.rfc-editor.org/rfc/rfc3986#section-5.2)). The [Open Graph protocol, basic metadata](https://ogp.me/#metadata), names four required properties: `og:title`, `og:type`, `og:image` and `og:url`. The tool treats a missing image as a failure (the card loses its picture), a missing title as a warning (platforms fall back), and a missing type or URL as information (platforms default to website and to the shared address). ### Image rules, in order 1. **No og:image** (FAIL): none of the five image keys is present. 2. **Relative address** (FAIL): the value does not start with a scheme. The protocol defines `og:image` as "An image URL"; platforms fetch it on their own, without the page as a base, so a relative value is not resolved by most. The preview resolves it anyway so you can see the picture; the suggested tags give the absolute address. 3. **Not a usable web URL** (FAIL): it resolves to something other than http or https. 4. **http:// on an https:// page** (CHECK). 5. **Did not load** (FAIL): our server fetches the image, following up to 3 redirects. It must answer with a success status, a content type of `image/png`, `image/jpeg`, `image/gif`, `image/webp` or `image/avif`, and at most 5 MiB. SVG, `application/octet-stream`, hotlink protection and oversize files fail here. 6. **Size**, decoded in the browser: either side under 200 px FAIL; under 600 × 315 CHECK (Facebook's small thumbnail); under 1200 × 630 INFO (soft on dense screens); otherwise PASS. 7. **Ratio** more than 0.25 from 1.91:1: INFO, large cards crop the edges. The size thresholds come from the platforms' own guidance, not from the protocol, which sets no size. ### Text, X and page rules | Rule | Severity | | --- | --- | | No og:title, or no og:description (names the fallback used) | CHECK | | No og:url, og:type or og:site_name | INFO | | og:title, og:description, og:image, og:url or meta description appears more than once | CHECK | | No twitter:card | INFO | | twitter:card not summary, summary_large_image, app or player | CHECK | | twitter:card summary with an image 600 px wide or more: X shows a small square | INFO | | No `<title>` | CHECK | | `<title>` over 60 characters | INFO | | No meta description | INFO | | Meta description over 160 characters | INFO | | og:url and the canonical link resolve to different addresses | CHECK | | meta robots contains noindex | CHECK | | No viewport meta tag | INFO | | A JSON-LD block that is not valid JSON | CHECK | The card types come from [X's Cards markup reference](https://developer.x.com/en/docs/x-for-websites/cards/overview/markup). The canonical link is defined by [RFC 6596, section 3](https://www.rfc-editor.org/rfc/rfc6596#section-3) ("the preferred version of a resource"); when og:url names a different address, share counts and search indexing split. A JSON-LD block must be valid JSON to be read at all ([JSON-LD 1.1, section 9](https://www.w3.org/TR/json-ld11/#json-ld-grammar)). ### The verdict In order: no image; image did not load; relative image; any other FAIL; an image under 600 × 315 (small image); otherwise ready to share, with platform limitations named. A page with a failing finding is never "Ready to share". ### Tags to add Only from what the page already says: og:title and og:description from the value the fallback order finds; og:url from the canonical link or the page address; og:type set to website; an absolute og:image when the existing one is relative; twitter:card summary_large_image when there is an image. A page with no description gets no og:description line. For pasted HTML, Heal it inserts the lines before `</head>`. ## Standards and conformance ### The Open Graph protocol Implemented: the four basic properties, the optional `og:description`, `og:site_name` and `og:image:url`, `og:image:secure_url` and `og:image:alt` structured properties, and first-wins for repeated properties. Not checked: `og:locale`, `og:video`, `og:audio`, object types beyond website, and `og:image:width`/`height` against the real image (the real size is measured instead). The protocol is a community specification with no versioned RFC; [ogp.me](https://ogp.me/) is its canonical text. ### X Cards Implemented: the four card types, the twitter:* keys and their fallback to Open Graph. X's renderer and cache are its own; the preview is an approximation. ### HTML Standard and RFC 6596 `<title>`, `<meta name="description">`, `<meta name="robots">`, `<meta name="viewport">`, `<base href>` and `<link rel="canonical">` are read as the HTML Standard and RFC 6596 define them. The 60 and 160 character lengths are search engines' observed cut-offs, not standards. ### RFC 3986 Relative image and canonical addresses are resolved as URI references against the base. ## Finding reference ### Images | Finding | Severity | What it means for whoever shares the link | Fix | | --- | --- | --- | --- | | No og:image | FAIL | No picture, or one the platform picks | Add a 1200 × 630 og:image with a full https:// address | | og:image is a relative URL | FAIL | Most platforms show no picture | Write the full address | | og:image is not a usable web URL | FAIL | No picture | Use an http or https address | | og:image did not load | FAIL | No picture | Fix the path, type or size of the image | | Image is n × n (under 200) | FAIL | Platforms drop it | Use 1200 × 630 | | Shown as a small thumbnail | CHECK | Small image beside the text | Use 1200 × 630 | | og:image uses http:// | CHECK | Some platforms refuse it | Serve it over https | | Image is n × n (under 1200 × 630) | INFO | Soft on dense screens | Use 1200 × 630 | | Image is n × n | PASS | Sharp on large cards | | | Image ratio is n:1 | INFO | Edges cropped | Use 1.91:1 | ### Text and page metadata | Finding | Severity | What it means for whoever shares the link | Fix | | --- | --- | --- | --- | | No og:title, No og:description | CHECK | Falls back to search text | Add them (Tags to add) | | No og:url, No og:type, No og:site_name | INFO | Platform defaults | Add them if they matter | | key appears n times | CHECK | Only the first is read | Remove the duplicate writer | | No twitter:card | INFO | X picks the layout | Add summary_large_image | | twitter:card "x" is not a card type | CHECK | X falls back | Use summary or summary_large_image | | X shows a small square | INFO | Wide image cropped to a square on X | Use summary_large_image | | No `<title>` | CHECK | Tabs and results show the address | Add a title | | Title is n characters | INFO | Cut in search results | Shorten to about 60 | | No meta description | INFO | Search writes a snippet | Add one | | Description is n characters | INFO | Cut in search results | Shorten to about 155 | | og:url and canonical disagree | CHECK | Shares and indexing split | Make them the same | | Page asks not to be indexed | CHECK | Dropped from search | Remove noindex if unintended | | No viewport meta tag | INFO | Desktop width on phones | Add one | | Structured data is not valid JSON | CHECK | Ignored by search engines | Fix the JSON | ## Guide ### No picture 1. Make a 1200 × 630 PNG or JPEG under 5 MiB, with the important part in the middle. 2. Add `<meta property="og:image" content="https://www.example.com/share/page.png">` inside `<head>`. 3. Check the page again: the large card should show it. Confirm outside Tamperbox: `curl -sI https://www.example.com/share/page.png` should show `200` and an `image/` content type. ### Small or cropped image Replace a square logo with a 1200 × 630 image. For X, set `twitter:card` to `summary_large_image`. ### Wrong title or description Add og:title and og:description written for a feed: what the page is, in a line. Use **Tags to add** as the starting point; for pasted HTML, Heal it inserts them. ### Duplicate tags Two plugins (an SEO plugin and a theme, for example) often both write Open Graph tags. View the source, find each writer, and switch one off. ### The platform still shows the old card Platforms cache cards. Use each platform's own refresh tool to fetch the link again, or share a new address. This tool shows what the page says now, not what a platform cached. ### Break it cases | Case | What it loads | What to look at | | --- | --- | --- | | No og:image | Your page's HTML without any image tag | Shares without a picture | | Relative image URL | Your page's HTML with og:image made relative | Fix the image address | | Only a `<title>` | Your page's HTML without Open Graph, Twitter and description tags | Missing tags; Heal it adds them | | Image too small | A sample page with a small image | Shown as a small thumbnail; the small card layout | | Image missing | A sample page whose image answers 404 | og:image did not load | The first three build on your own input: the HTML you pasted, or the HTML your address returned. Break it replaces the field with an adapted input or a labelled fixture. Use History to Revert the latest change or Reset input to the starting input; restoring a live address runs a new check. ## Worked example The page opens with a live fetch of `tamperbox.dev`, followed by its selected preview image when present. The metadata and image can change, so use the displayed evidence rather than expecting a fixed title, size or finding count. Read the source tag named beside each field. A fallback title can make the preview look complete while the explicit Open Graph tag is missing. Compare the large card, X, chat and search layouts, then read Findings and Tags found. These are approximations made from one fetched HTML response; they do not reproduce a platform's cache or execute the page's scripts. Use **No picture** or another Break it case to inspect missing metadata, then review the suggested tags. When working with pasted HTML, the repair modifies only the text in the tool. Publish changes through your own site workflow and fetch the page again. If the real platform still shows an old card, use its refresh/debug tool; rerunning Tamperbox does not purge that platform's cache. ## For agents Use the Tamperbox MCP `search` tool to inspect the schema, then `execute` with `tamperbox.request` to call `POST /v1/tools/open_graph_preview`. Supply the required `url` field as a full public HTTP or HTTPS URL. The operation is named `open_graph_preview`; the browser page’s hyphenated identifier is not the API operation name. The response contains fetched `evidence`, extracted `meta`, a resolved `card` and `checks`. Unlike the browser preview, the operation does not fetch and decode the image or verify its dimensions, and it never executes page scripts. Keep the input, observation time, source limitations and inconclusive results with any summary. Browser fixtures are demonstrations, not live MCP targets. Do not turn missing evidence into a passing check or infer that an inaccessible resource has been deleted. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/), [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) and [Security and privacy](https://docs.tamperbox.dev/reference/security/). ## Limits - One fetch of the page (512 KiB) and its image (5 MiB, PNG, JPEG, GIF, WebP or AVIF). - Scripts do not run; tags a script adds are not seen. - Search cuts are by character count, close to but not the same as pixel widths. - Platforms cache cards; this tool cannot refresh them. - Live fetches are rate limited. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. ## References - [The Open Graph protocol](https://ogp.me/): [basic metadata](https://ogp.me/#metadata), [structured properties](https://ogp.me/#structured), [arrays](https://ogp.me/#array). - [X Cards markup reference](https://developer.x.com/en/docs/x-for-websites/cards/overview/markup). - [HTML Standard, the meta element](https://html.spec.whatwg.org/multipage/semantics.html#the-meta-element) and [the base element](https://html.spec.whatwg.org/multipage/semantics.html#the-base-element). - [RFC 6596, The Canonical Link Relation](https://www.rfc-editor.org/rfc/rfc6596#section-3), section 3. - [RFC 3986, URI Generic Syntax](https://www.rfc-editor.org/rfc/rfc3986#section-5.2), section 5.2. - [JSON-LD 1.1](https://www.w3.org/TR/json-ld11/#json-ld-grammar), section 9. --- # Open Port Checker How the Open Port Checker tests one TCP port on your own public address from the internet, what open, refused and no answer mean for a port forward, and how to fix each outcome. Canonical: https://docs.tamperbox.dev/tools/open-port-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A browser on the connection to test, and a TCP port from 1 to 65535 Outputs: Open, refused or no answer for the port on the visitor's own public address, with the connect time, findings for UDP-only and commonly blocked ports, and the steps for that outcome Limitations: Tests only the public address the request came from (a VPN exit or carrier-grade NAT gateway when present); TCP only; one region; no answer is inconclusive The tool page is [tamperbox.dev/open-port-checker](https://tamperbox.dev/open-port-checker). It opens ready to check port 25565, the Minecraft Java default, and tests it only when you press Check port. This page is the long version: which address is tested and why only that one, how the single connection is classified, what each outcome means for a port forward, and how to confirm a fix. <div class="tb-callout"><strong>Where processing happens:</strong> choosing a port, the common-port chips and Break it are handled in your browser and send nothing. Opening the page asks the Tamperbox server for your public address. Pressing Check port asks the server to open one TCP connection to that address on that port; it sends no application data over the connection. The page keeps measurements and input changes in memory until reload; explicit tool transfers may use temporary session storage. The address is never taken from anything you type, so the tool cannot be pointed at someone else.</div> ## What the tool answers 1. **Can our measurement region reach this port on my connection?** Open, refused, or no answer. 2. **What does that mean for my setup?** The service, the address it listens on, the router forward, a firewall, carrier-grade NAT or a VPN. 3. **Is there a catch for this port?** A UDP-only service the TCP test cannot see, or a port home providers often block. ## Inputs ### A port A number from 1 to 65535, typed or chosen from the common ports: 22 (SSH), 80 (HTTP), 443 (HTTPS), 3389 (Remote Desktop), 25565 (Minecraft), 32400 (Plex), 8096 (Jellyfin) and 8080 (an alternative web port). Anything else is refused with a message naming the invalid value and the valid range, 1 to 65535. The check runs only on Enter or the Check port button; changing the port says what will be tested and waits. ### Your address Not an input. The server takes the address the request came from: the `CF-Connecting-IP` value, or the IPv6 address when the edge replaced it with a pseudo IPv4 address. The page shows it under "To your public address" once it has been read. If that address is not public, the check is refused. ## Reading the result ### Verdict and chips "Ready to check port N on your public IP" until you press Check port, then one of "Port N is open on …", "Port N is closed on …" or "No answer on port N on …". The chip names the outcome and scrolls to the steps. ### Findings A separate Findings panel follows the verdict. It explains the measured outcome, warns about UDP-only ports, notes ports commonly filtered by providers, and states which public address was tested. Passing findings are folded; CHECK and FAIL findings count toward the number to check. The [finding reference](#finding-reference) maps their wording and severity. ### The probe line From our server in Eastern North America to your public address on the port: "Not checked yet", "Connecting…", then "Open" with the connect time, "Refused" or "No answer". ### What to do next Numbered steps written for the outcome and the port, with a note when the port is UDP-only or often blocked. ### Checked on this visit The last twelve checks, newest first, with their outcome and time. Kept in the page only; reloading clears it. ### History History records input changes made by Break it and Heal it. It appears after the complete result and before Take it further. Revert undoes the newest change; Reset input returns to the input before the first retained change. Restore input before this break is also available in Heal it when there is a change to undo. Restoring does not create another history entry. This history is held in the page and disappears on reload. Here the changed value is the port. Restoring it does not spend a probe. History is separate from Checked on this visit, which records measurement outcomes rather than edits. ### Take it further These links carry values derived from the current result. A link is absent when its required evidence is missing; the tool does not invent a target. | Destination | Value and condition | | --- | --- | | [TCP Ping](https://docs.tamperbox.dev/tools/tcp-ping/) | The observed address and port, after an open result | | [Minecraft Server Status](https://docs.tamperbox.dev/tools/minecraft-server-status/) | The observed address, only after port 25565 is open | | [ASN Lookup](https://docs.tamperbox.dev/tools/asn-lookup/) | The observed public address, when available | These links use the observed public address rather than a user-supplied target. The destination applies its own input rules; measurement tools still wait for an explicit run. ### What this result means Six cards explain the current findings: Ask your agent, In plain words, What does it mean?, What good looks like, How to fix it, and Tool limitations. Expand a card to read the explanation and its method or guide link. Copying an agent prompt does not run another check. The cards interpret the evidence already shown; they are not an additional measurement or an independent confirmation. When the input is cleared, a check fails, or no result is available, result-specific cards clear and contextual links disappear. Read the verdict before relying on a card, and distinguish a missing observation from a confirmed negative result. ## Method ### 1. The address The address comes from the request, never from the page. That is why the tool cannot scan other machines, and why a VPN or proxy changes what is tested: the server sees the exit of the tunnel, not your router. With carrier-grade NAT ([RFC 6598, section 4](https://www.rfc-editor.org/rfc/rfc6598#section-4)), the address belongs to your provider's gateway, which may be shared by many customers. A local router rule alone does not configure the upstream NAT; provider support, an assigned public address or an approved tunnel may be needed. ### 2. One connection The server asks the measurement service in Eastern North America to make one TCP connection to the address and port, limited to 1.5 seconds. A completed three-way handshake ([RFC 9293, section 3.5](https://www.rfc-editor.org/rfc/rfc9293#section-3.5)) is closed at once; nothing is sent. | Outcome | What came back | Wording | | --- | --- | --- | | Open | The handshake completed | "Port N is open", with the connect time | | Closed | A reset (`ECONNREFUSED`) | "Port N is closed": something answered and said no | | No answer | Nothing within 1.5 seconds, or an unreachable error | "No answer on port N": inconclusive | | Unavailable | The measurement did not complete | "The check is unavailable" | A reset means a device answered for the port but nothing accepted the connection: [RFC 9293, section 3.5.2](https://www.rfc-editor.org/rfc/rfc9293#section-3.5.2) says "A SYN segment that does not match an existing connection is rejected by this means". Silence means the SYN or its answer was dropped, which a missing forward, a firewall and carrier-grade NAT all cause. ### 3. Port caveats | Port | Caveat | Why | | --- | --- | --- | | 51820, 1194, 19132, 3478, 500 | UDP service | WireGuard, OpenVPN's default mode, Minecraft Bedrock, STUN and IPsec use UDP; a TCP result says nothing about them | | 25, 135, 137, 139, 445 | Often blocked by providers | Inbound mail and Windows file-sharing ports are commonly filtered on home connections | ### 4. Steps per outcome The steps under What to do next follow the outcome: for open, confirm you meant it and keep the service updated; for refused, start the service, listen on the network rather than localhost, and point the forward at the right device; for no answer, add the forward, allow the port in the device's firewall, compare the router's WAN address for carrier-grade NAT, and turn off any VPN. <span id="standards"></span> ## Standards and conformance | Specification | Sections used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 9293](https://www.rfc-editor.org/rfc/rfc9293) TCP | [3.5](https://www.rfc-editor.org/rfc/rfc9293#section-3.5), [3.5.2](https://www.rfc-editor.org/rfc/rfc9293#section-3.5.2) | Handshake completed is open; a reset is refused | No data exchanged; obsoletes [RFC 793](https://www.rfc-editor.org/rfc/rfc793) | | [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598) shared address space | [4](https://www.rfc-editor.org/rfc/rfc6598#section-4) | Explains why a WAN address from 100.64.0.0/10 cannot take a forward | The tool does not read your router's WAN address | | [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3) private addresses | 3 | Devices on your home network are never tested directly | | | [RFC 6887](https://www.rfc-editor.org/rfc/rfc6887#section-1) Port Control Protocol | 1 | Background: forwards can also be created automatically (UPnP, NAT-PMP, PCP); the test sees the result either way | | ## Finding reference | Finding | Severity | What it means for the device behind the port | Fix | | --- | --- | --- | --- | | Port N accepts connections from the internet | PASS | The measurement region connected; other sources may be filtered | Keep it updated; close the forward when not needed | | Port N refused the connection | FAIL | The forward or device answers, but nothing listens | Start the service; bind to the network; fix the forward target | | No answer on port N | CHECK | Dropped before anything answered: no forward, a firewall, CGNAT or a VPN | Add the forward; allow it in the firewall; check for CGNAT | | … uses UDP | CHECK | The TCP result says nothing about this UDP service | Test the UDP service from outside with the app itself | | Port N is often blocked by home providers | INFO | The provider may filter it before your router | Ask the provider or use another port | | This tests the address our server sees | INFO | A VPN, proxy or CGNAT gateway is tested instead of your router | Turn the VPN off; ask for a public address | ## Guide ### A game or media server friends cannot reach 1. On the device, confirm the service listens on the network: ```sh ss -ltn | grep ':25565' ``` On Windows, `netstat -an | findstr 25565`. A line with `127.0.0.1` means it listens only locally. 2. In the router, forward TCP to the device's LAN address, and reserve that address so it does not change after a restart. 3. Allow the port in the device's firewall. 4. Press Check port. Open confirms the measurement region completed a TCP connection. Friends may still be filtered or rejected by the application; refused or no answer suggest which steps to revisit. ### The chain a connection has to cross A connection from the internet to a game or media server at home passes five places, and each outcome points at one of them: | Hop | What has to be right | What fails there looks like | | --- | --- | --- | | Your provider | It gives your router a public address and does not filter the port | No answer: carrier-grade NAT or an inbound block | | The router | A forward (or UPnP mapping) for the port and protocol, to the device's current LAN address | No answer: no forward. Refused: a forward to a device where nothing listens | | The device's firewall | An inbound rule allowing the port | No answer: the firewall drops it silently | | The service | Running, and listening on the network address or `0.0.0.0` | Refused: nothing listening, or listening only on `127.0.0.1` | | The application | Accepts the client after the connection | Open here, but the app still rejects players (whitelist, version, password) | Work from the service outwards: first confirm it listens on the device, then the firewall, then the router, then the provider. Each step is checked again with this tool, so you know which hop the problem was in. ### No answer even with a forward Open the router's status page and compare its WAN address with the address shown here. If they differ, or the WAN address is between 100.64.0.0 and 100.127.255.255, your provider uses carrier-grade NAT: ask for a public address, or use a tunnel service. If a VPN is on, turn it off and check again. ### Confirm from outside without Tamperbox From a machine on another network (a phone hotspot works): ```sh nc -vz -w 2 <your public address> 25565 ``` ### Trying another port Select a common-port button or enter a port from 1 to 65535. This stages the target but does not send a probe until you press Check port or Enter. Results from earlier checks remain in Checked on this visit, up to twelve entries, and disappear on reload. Compare the target address and timestamp before interpreting repeated results. ### Break it and restore the port | Case | Port loaded | What to expect before running | | --- | --- | --- | | A UDP-only port | 51820 | A UDP caveat; a TCP check cannot establish WireGuard reachability | | Often blocked by providers | 25 | A note about common inbound filtering | | Port out of range | 70000 | An invalid-port verdict and a disabled Check port button | These controls change the port without making a connection. Revert in History or Restore input before this break in Heal it restores the prior port; Reset input undoes the retained changes. Press Check port only when you intend to test the restored valid port. ## Worked example The page starts ready to test TCP port 25565 on the request-source address. Nothing has been probed yet. After Check port, read the address actually tested and the outcome: handshake completed, explicit refusal, no answer or unavailable measurement. Suppose the first attempt receives no answer. That alone cannot identify a missing port forward, a stopped service or a firewall. Confirm the service is listening, compare your router WAN address with the observed address, and inspect the intended firewall and forwarding rules. After a deliberate configuration change, repeat the check. An open result proves reachability from the measurement region, not from every network, and does not establish that the application accepts logins or game sessions. ## For agents The Tamperbox MCP server exposes the same check as `open_port_checker`, but it tests the public address of whoever makes the request: called through an agent or gateway, it tests the public request source, not necessarily the user's connection. Interpret it as a test of the request source seen by the gateway; that may be shared egress rather than the machine the agent runs on, and keep these warnings: - No answer is inconclusive. - A VPN, proxy or CGNAT gateway is tested in place of the router behind it. - TCP only. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/), and [Security and privacy](https://docs.tamperbox.dev/reference/security/). [TCP Ping](https://docs.tamperbox.dev/tools/tcp-ping/) tests any public server from three regions. ### Transfers to another tool Explicit sibling-tool controls can carry the current input or observed address to another page. The shared navigation stores that value temporarily in tab-scoped `sessionStorage`, accepts a transfer for at most one minute, and puts a random transfer token in the URL fragment. The input itself is not placed in the URL. The receiving page consumes the transfer and applies its own input rules; tools with a manual Run button still require that action for live checks. This is not a saved result, and the destination can send the value to the services it needs. Ordinary edits and lookups do not create a durable report archive. ## Limits - Your own public address only; no other address can be entered. - One TCP connection from one region, limited to 1.5 seconds. - UDP cannot be tested. - The history of checks is kept in the page only. - The page keeps results in memory. Explicit transfers to another tool use temporary session storage. ## References - [RFC 9293](https://www.rfc-editor.org/rfc/rfc9293), Transmission Control Protocol: sections 3.5 and 3.5.2. Obsoletes [RFC 793](https://www.rfc-editor.org/rfc/rfc793). - [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598), IANA-Reserved IPv4 Prefix for Shared Address Space: section 4. - [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918), Address Allocation for Private Internets: section 3. - [RFC 6887](https://www.rfc-editor.org/rfc/rfc6887), Port Control Protocol: section 1. --- # Operation catalog The expanded Tamperbox API catalog groups 114 operations across artifact analysis, builders, diagnostics, and workflows. Canonical: https://docs.tamperbox.dev/reference/operations/ Updated: 2026-10-20 Applies to: MCP 0.3.0 Outputs: An operation family to inspect with search Limitations: Counts and schemas can change with later product releases. The expanded catalog contains 114 operations representing all 53 public website tool entries. Use `search` for the exact schema bundled with your MCP server, or read the [REST OpenAPI specification](https://api.tamperbox.dev/v1/openapi.json). Older installed packages can contain an earlier catalog. Remote artifact operations send inputs to our server, even when they make no network lookup. Use the browser tools for sensitive local documents or secrets. History, clipboard actions and visual rendering are interface features, not REST operations. ## Transforms `jwt_decode`, `json_format`, `json_to_yaml`, `timestamp_to_iso`, and `api_convert` accept text artifacts plus operation-specific options. Decoding and conversion do not establish trust or lossless equivalence. The browser tools document the full methods for the [JWT Decoder & Verifier](https://docs.tamperbox.dev/tools/jwt/), the [Unix Timestamp Converter](https://docs.tamperbox.dev/tools/unix-timestamp/) and the [Postman Collection Converter](https://docs.tamperbox.dev/tools/postman-converter/), including every finding and what a decoded or converted artifact does not prove. `jwt_verify` requires an explicit algorithm and key; signature and claim checks are separate. `jwt_rebuild` supports HMAC re-signing and explicitly unsigned or stale fixtures. `jwt_fixture` can generate a synthetic asymmetric test token without retaining its private key. None establishes application authorization. `timestamp_convert` handles batches, units, time zones, exports and nanosecond precision; `timestamp_adjust` supports format input, duration edits, calendar boundaries and code snippets. Nanoseconds are decimal strings in JSON. `api_convert_report` adds environments, redaction options, conversion notes and request previews without executing any requests. ## Email and DNS Email-domain, provider, SPF, DMARC, DKIM, MTA-STS, BIMI, and record lookup operations inspect public DNS and related policy evidence. DNS configuration is not proof of mailbox existence or delivery. The browser tools document the full methods for [MX routing](https://docs.tamperbox.dev/tools/email-domain/), [email-provider identification](https://docs.tamperbox.dev/tools/email-provider/), [SPF](https://docs.tamperbox.dev/tools/spf-checker/), [DMARC](https://docs.tamperbox.dev/tools/dmarc-checker/), [DKIM](https://docs.tamperbox.dev/tools/dkim-checker/), [MTA-STS and TLS-RPT](https://docs.tamperbox.dev/tools/mta-sts-checker/), and [BIMI](https://docs.tamperbox.dev/tools/bimi-checker/), including every finding and its delivery impact. The [Email Header Analyzer](https://docs.tamperbox.dev/tools/email-header-analyzer/) documents the separate case of reading route and authentication evidence from a supplied message. The corresponding `*_analyze` operations accept pasted evidence without resolving its names. Policy `*_build` operations produce drafts without publishing DNS. `dkim_discover` checks a bounded selector list or extracts a selector from a supplied signature header; it cannot discover every possible selector. `ip_enrich` supplies public reverse-DNS and network-ownership evidence. ## Hosting, TLS, and HTTP Hosting, technology, CDN, certificate, header, redirect, CORS, mixed-content, HTTP/3, and uptime operations observe public endpoints from the service's vantage point. Proxies, regional differences, and unavailable probes can limit conclusions. The certificate operation's findings are explained one by one in the [SSL Certificate Checker](https://docs.tamperbox.dev/tools/ssl-checker/) page. The redirect, HTTP/3 and CORS operations are documented the same way on the [Redirect Checker](https://docs.tamperbox.dev/tools/redirect-checker/), [HTTP/3 & Compression Checker](https://docs.tamperbox.dev/tools/http3-checker/) and [CORS Tester](https://docs.tamperbox.dev/tools/cors-tester/) pages, including what a probe from the service's vantage point does not establish about a visitor's browser. For those three pages, the exact live operations are `redirect_checker`, `http3_checker` and `cors_tester`. Each accepts a public URL, rejects private or reserved targets, and returns structured evidence with warnings and provenance. `cors_tester` additionally requires an explicit origin and never sends a mutating request; `http3_checker` separates HTTP/3 advertisement from a successful transport probe. Artifact counterparts accept supplied headers, HTML, handshake transcripts and certificates. `tls_probe` adds supported mail TLS and STARTTLS ports. Cookie, metadata and post-quantum operations expose analysis and draft repairs or configuration text. Pasted evidence does not independently verify a live server. ## Network and registration IP, ASN, BGP, port, TCP, WHOIS, RDAP, reverse-DNS, and domain-availability operations return bounded observations. Caller-context checks can describe the MCP host or shared gateway rather than the human user's device. `bgp_events` exposes reported potential routing incidents. It requires the incident feed to be configured on the server; `feed_unavailable` does not mean there were no incidents. ## Published site files The catalog includes live and pasted checks for `robots.txt`, `ads.txt` and `llms.txt`, explicit formatting repairs, crawler-rule simulation and guide drafting. `site_file_inspect` also supports `app-ads.txt` and `llms-full.txt`; `sitemap_inspect` and `sellers_inspect` expose sitemap and seller evidence. Embedded links are not fetched by artifact-only operations. ## Workflow utilities `tamperbox_pipeline`, `tamperbox_find`, and `get_recipe` support pipeline execution, directory search, and recipe retrieval. Fetching a recipe does not execute it. --- # Post-Quantum TLS Checker How the post-quantum checker runs two TLS handshakes, how it classifies the key exchange group, what each finding means for recorded traffic, and how to turn on ML-KEM and confirm it. Canonical: https://docs.tamperbox.dev/tools/post-quantum-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A host name that serves HTTPS on port 443, or the output of openssl s_client or curl -v to paste Outputs: A verdict with chips, findings worst first, the key exchange broken into its parts, both handshakes side by side, what the key exchange protects, and a server configuration that puts X25519MLKEM768 first Limitations: Two connections from one location at one moment, on port 443 only; the probe's default group offer is not a browser ClientHello; a failed ML-KEM-only handshake does not prove lack of support; certificate signatures are not assessed The tool page is [tamperbox.dev/post-quantum-checker](https://tamperbox.dev/post-quantum-checker). It opens by checking `tamperbox.dev` live and answers one narrow question: is the session key of a TLS connection to this host protected against a future quantum computer? This page is the long version: what the two handshakes do, how a group name is classified, every finding the page can show, and how to turn ML-KEM on and confirm it without Tamperbox. <div class="tb-callout"><strong>Where processing happens:</strong> a host name is sent to the Tamperbox server, which opens two TLS connections to it on port 443 and returns what each handshake negotiated. Pasted handshake output is read in your browser and never uploaded. History and tool-to-tool transfers remain in the browser; see Browser transfers below.</div> ## What the tool answers Three questions, in the order the result answers them: 1. **Which key exchange group does the server choose?** The first handshake offers the probe's default list, classical and hybrid groups together, and the server picks one. This decides the verdict. 2. **Can the server use ML-KEM at all?** The second handshake offers only the three ML-KEM hybrids, so the server either completes it with one of them or refuses. This separates "not supported" from "supported but not preferred". 3. **What does that protect?** The session key, not the certificate. The result says whether a recording of the traffic could be decrypted later, and what to change on the server when it could. The question is deliberately narrow. Certificate trust, names and expiry belong to the [SSL Certificate Checker](https://docs.tamperbox.dev/tools/ssl-checker/). ## Inputs ### A host name `example.com` or `www.example.com`. The check runs when you stop typing, or on Enter, and costs two connections from our server to port 443. A pasted address is reduced to its host by the shared paste cleanup: `https://example.com/login` becomes `example.com`, an email address becomes its domain, quotes and brackets are dropped. Text that fits none of these stays as pasted so the error can explain it. ### A host name with a port `:443` is accepted and removed. Any other port is refused, because the probe speaks HTTPS only: | Input | What happens | | --- | --- | | `example.com:443` | Checked as `example.com` | | `example.com:8443` | Refused: "Only port 443 is checked". Heal it offers **Check port 443** | | `mail.example.com:25`, `:465`, `:587`, `:993`, `:995` | Refused with the `openssl s_client` command for that mail port, so you can paste its output instead | ### Pasted handshake output Anything that looks like a handshake, or any multi-line text, is read in the browser. The parser takes the protocol, the cipher, the group, ALPN, the verification code, a TLS alert and any PEM certificates. The group comes from `Negotiated TLS1.3 group`, `Peer Temp Key` or `Server Temp Key` in `openssl s_client` output, or from the third field of `SSL connection using` in `curl -v`. `<NULL>` counts as no group. If the paste includes the command line, `-servername` or `-connect` names the host and `-groups` names what was offered. Output with no protocol, group or alert is refused: "No TLS handshake found." ### Files A `.txt` file up to 128 KiB can be dropped or opened. It is read in the browser like a paste. ## Reading the result ### Verdict and chips The verdict line names the outcome: **Post-quantum secure**, **Not post-quantum secure**, **Post-quantum capable**, **Key exchange not recognised** or **No TLS handshake completed**. The detail names the group and, for a live check, the host and the time of the check. Chips repeat the group, the TLS version, the ML-KEM-only result and the certificate's classical key; each one scrolls to its evidence. ### Findings One finding per question, worst first. Passes fold into one line, "n checks passed", which opens on click. The [finding reference](#finding-reference) lists every title. ### History and Take it further History logs each Break it load, with Revert for the newest change and Reset input to return to what you entered. Take it further carries derived values into the same category: the host with port 443 into the DANE checker, and, for pasted output, the host named in the command into the SSL Certificate Checker. ### The key, the handshakes, what it protects **The key the probe negotiated** splits the group into its parts: a classical part and a post-quantum part, with an empty "Nothing" slot when there is no post-quantum part. **Two handshakes** shows each attempt: what was offered, what came back, and why. **What it protects** states whether traffic recorded today could be read later, the TLS version, and the certificate key. **Turn on ML-KEM** appears only when the server should change, with a configuration for nginx, Apache, Caddy, HAProxy or Go. ### Browser transfers Explicit tool links temporarily place the transferred input in browser `sessionStorage`. The URL fragment carries a random token, not the input. The receiving page accepts that token once, for its destination path and for less than one minute, then removes it from the address. A same-origin browser channel can complete a transfer into another tab. Ordinary documentation links do not transfer input. When browser storage is unavailable, navigation still works but the input may need to be pasted again. ## Method The rules live in `assessPostQuantum` and `groupInfo` in the page's TLS library; the probe is `openssl s_client` on the Tamperbox server. ### The two handshakes | Handshake | Command options | Counts as success when | | --- | --- | --- | | Default client | `-servername host -verify_hostname host -showcerts -alpn h2,http/1.1` and OpenSSL's default group list | Any group is reported | | ML-KEM only | The same, plus `-tls1_3 -groups X25519MLKEM768:SecP256r1MLKEM768:SecP384r1MLKEM1024` | TLS 1.3 completes, a certificate comes back and the group is one of the three | Both run in parallel with a 12 second deadline. The ML-KEM-only result is reported as accepted or "Not shown", never "not supported": [RFC 9846, Section 2.1](https://www.rfc-editor.org/rfc/rfc9846#section-2.1) requires that "If no common cryptographic parameters can be negotiated, the server MUST abort the handshake with an appropriate alert", but an abort has other causes too (a firewall, a TLS 1.2-only front end, a timeout), so a refusal is not proof. ### Classifying a group Each name is looked up, case-insensitively, in a fixed catalog: | Kind | Names | Post-quantum | | --- | --- | --- | | Hybrid | X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024 | Yes | | ML-KEM alone | MLKEM512, MLKEM768, MLKEM1024 | Yes | | Obsolete draft | X25519Kyber768Draft00, X25519Kyber512Draft00 | No | | Classical | X25519, X448, P-256 (also secp256r1, prime256v1), P-384, P-521, ffdhe2048, ffdhe3072, DH | No | | Unknown | Anything else | Not claimed | The hybrids are defined in [RFC 10024, Section 7](https://www.rfc-editor.org/rfc/rfc10024#section-7); the draft codepoints are marked obsolete by [RFC 10024, Section 7.4](https://www.rfc-editor.org/rfc/rfc10024#section-7.4). An unknown name is never guessed at. ### Deciding the verdict The first matching rule decides: | Order | Condition | State | Verdict | | --- | --- | --- | --- | | 1 | Default group is hybrid or ML-KEM alone | `secure` | Post-quantum secure | | 2 | Default group is a Kyber draft | `obsolete` | Not post-quantum secure | | 3 | Protocol older than TLS 1.3 | `tls12` | Not post-quantum secure | | 4 | Default group unknown | `unknown-group` | Key exchange not recognised | | 5 | Default group classical, ML-KEM-only accepted | `prefers-classical` | Not post-quantum secure | | 6 | Default group classical, ML-KEM-only not shown | `classical` | Not post-quantum secure | | 7 | No default group, ML-KEM-only accepted | `secure-only` | Post-quantum capable | | 8 | Neither gave a group | `no-handshake` | No TLS handshake completed | Rule 3 follows from [RFC 9954, Section 3.1](https://www.rfc-editor.org/rfc/rfc9954#section-3.1): hybrid groups are negotiated through the TLS 1.3 `supported_groups` and `key_share` extensions ([RFC 9846, Section 4.3.7](https://www.rfc-editor.org/rfc/rfc9846#section-4.3.7) and [Section 4.3.8](https://www.rfc-editor.org/rfc/rfc9846#section-4.3.8)), which TLS 1.2 does not use for this purpose. A paste is one handshake, so only rules 1 to 4, 6 and 8 can apply to it. ## Standards and conformance The tool observes; it is not a TLS implementation. OpenSSL on our server performs the handshakes, and the page judges the reported group. ### RFC 9846: TLS 1.3 [RFC 9846](https://www.rfc-editor.org/rfc/rfc9846) is the current TLS 1.3 specification and obsoletes RFC 8446. | Section | Rule | What the tool does | | --- | --- | --- | | [2](https://www.rfc-editor.org/rfc/rfc9846#section-2) | "the server's share MUST be in the same group as one of the client's shares" | Reports the group the server's share used | | [2.1](https://www.rfc-editor.org/rfc/rfc9846#section-2.1) | No common parameters: abort with an alert | A refusal is shown as "Not shown", and a pasted alert is named | | [4.3.7](https://www.rfc-editor.org/rfc/rfc9846#section-4.3.7) | Client lists supported groups | The ML-KEM-only handshake restricts the list to three hybrids | | [4.3.8](https://www.rfc-editor.org/rfc/rfc9846#section-4.3.8) | Key share per offered group | Not inspected byte by byte; only the negotiated group is read | ### RFC 10024: ML-KEM hybrids in TLS 1.3 [RFC 10024](https://www.rfc-editor.org/rfc/rfc10024), a Proposed Standard, defines the three hybrids the probe offers. [Section 4.3](https://www.rfc-editor.org/rfc/rfc10024#section-4.3) fixes the shared secret: "For X25519MLKEM768, the shared secret is the concatenation of the ML-KEM shared secret and the X25519 shared secret." The tool names both parts but does not verify the concatenation; that is the TLS library's job. [Section 7.1](https://www.rfc-editor.org/rfc/rfc10024#section-7.1) marks X25519MLKEM768 as Recommended, which is why the configuration puts it first. ### RFC 9954 and FIPS 203 [RFC 9954](https://www.rfc-editor.org/rfc/rfc9954) (Informational) is the hybrid design the hybrids follow. [Section 3.2](https://www.rfc-editor.org/rfc/rfc9954#section-3.2) says the client's shares are listed in preference order and "the server selects one algorithm". That selection is what the default handshake observes, and why a server that supports ML-KEM can still pick X25519. [FIPS 203](https://csrc.nist.gov/pubs/fips/203/final) (August 2024) defines ML-KEM itself; the tool relies on it only for the names ML-KEM-768 and ML-KEM-1024. ### Where the tool stops - Pure ML-KEM groups are classified, but the probe does not offer them: [draft-ietf-tls-mlkem](https://datatracker.ietf.org/doc/draft-ietf-tls-mlkem/) is still a draft. - HelloRetryRequest is not reported separately; a server that asks for another share still ends with one group. - Certificate signatures are classical everywhere today and are not judged. - Group names are read as OpenSSL prints them; see the [TLS Supported Groups registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8) for codepoints. ## Finding reference Every finding id the page emits, grouped by the question it answers. ### Key exchange group | Title | Severity | Basis | Meaning | Fix | | --- | --- | --- | --- | --- | | ML-KEM key exchange: *group* | PASS | [RFC 10024, 7](https://www.rfc-editor.org/rfc/rfc10024#section-7) | Recorded traffic stays protected | None | | Classical key exchange: *group* | FAIL | [RFC 9954, 3.2](https://www.rfc-editor.org/rfc/rfc9954#section-3.2) | Recorded traffic can be decrypted later | Put X25519MLKEM768 first | | Obsolete Kyber draft: *group* | FAIL | [RFC 10024, 7.4](https://www.rfc-editor.org/rfc/rfc10024#section-7.4) | Browsers no longer offer it and fall back to classical | Replace with X25519MLKEM768 | | Key exchange not recognised: *group* | CHECK | Catalog | No claim either way | Look the name up in the registry | | Default-client handshake gave no group | CHECK | [RFC 9846, 2.1](https://www.rfc-editor.org/rfc/rfc9846#section-2.1) | Ordinary clients' result unknown | Check again | | Handshake refused: *alert* | CHECK | [RFC 9846, 2.1](https://www.rfc-editor.org/rfc/rfc9846#section-2.1) | The offered groups had no match | Run without `-groups` | | No key exchange reported | CHECK | | Nothing to judge | Confirm HTTPS on 443 | ### Protocol, preference and certificate | Title | Severity | Basis | Meaning | Fix | | --- | --- | --- | --- | --- | | TLS 1.3 negotiated | PASS | [RFC 9954, 3.1](https://www.rfc-editor.org/rfc/rfc9954#section-3.1) | Hybrids are possible | None | | TLS 1.2 cannot carry ML-KEM | FAIL | [RFC 9954, 3.1](https://www.rfc-editor.org/rfc/rfc9954#section-3.1) | No hybrid on this connection | Turn TLS 1.3 on | | Prefers a classical group over *hybrid* | CHECK | [RFC 9954, 3.2](https://www.rfc-editor.org/rfc/rfc9954#section-3.2) | Support exists but is not chosen | Reorder the group list | | Accepts *hybrid* when it is the only choice | PASS | [RFC 10024, 4](https://www.rfc-editor.org/rfc/rfc10024#section-4) | Support confirmed | None | | ML-KEM-only handshake did not complete | INFO | [RFC 9846, 2.1](https://www.rfc-editor.org/rfc/rfc9846#section-2.1) | Not proof of no support | Read with the default result | | Certificate signature stays classical | INFO | | Signatures only need to hold during the handshake | None | ## Guide ### Classical key exchange 1. Find what terminates TLS: a CDN, a load balancer or the web server. Its settings decide the result. 2. Upgrade the TLS library: OpenSSL 3.5 or later for nginx, Apache and HAProxy; Go 1.24 or later; Caddy 2.10 or later. 3. Put the hybrid first. For nginx: `ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1;`. The tool shows the line for Apache (`SSLOpenSSLConfCmd Curves`), HAProxy (`ssl-default-bind-curves`), Caddy (`curves`) and Go (`CurvePreferences`). 4. Reload and confirm independently: ```sh openssl s_client -connect example.com:443 -servername example.com -groups X25519MLKEM768 </dev/null 2>/dev/null | grep -E 'Negotiated TLS1.3 group|Protocol' ``` An OpenSSL 3.5 client prints `Negotiated TLS1.3 group: X25519MLKEM768` when the server accepts it. ### Prefers a classical group The server already has ML-KEM. An old group list puts X25519 first, so the server picks it whenever both are offered. Move X25519MLKEM768 to the front and check again. Run the command above without `-groups` to see the server's choice against OpenSSL's default offer. ### TLS 1.2 or an obsolete draft TLS 1.2 is usually an old `ssl_protocols` line or a load balancer security policy; enable TLS 1.3 first. A Kyber draft means a TLS library or proxy older than the standard; upgrade it and list X25519MLKEM768 instead. ### Break it cases | Button | What it loads | Expected verdict | | --- | --- | --- | | Classical X25519 | Your host, `Peer Temp Key: X25519` | Not post-quantum secure | | Obsolete Kyber draft | Your host, X25519Kyber768Draft00 | Not post-quantum secure | | TLS 1.2 only | Your host, TLS 1.2 and X25519 | Not post-quantum secure | | P-256 hybrid | Your host, SecP256r1MLKEM768 | Post-quantum secure | | Handshake refused | `-groups X25519MLKEM768` and a handshake failure alert | No connection | Each case is built from your host and cipher and read locally; History restores your input. Heal it offers **Check port 443** for a wrong port. ## Worked example The page opens on `tamperbox.dev`, checked live. Values change with the server's configuration, so read this as a guide to the shape, not as fixed facts. Read the negotiated group and protocol from the current result, then compare the default handshake with the ML-KEM-only attempt. A hybrid result combines a classical group with ML-KEM; it does not make the certificate signature post-quantum. Findings explain missing support, preference or probe limitations, and configuration advice appears only when the result calls for it. Take it further offers the DANE check for `tamperbox.dev:443`. To see the repair path, press **Classical X25519**. The input becomes an `openssl s_client` transcript for your host with `Peer Temp Key: X25519`; the verdict turns to **Not post-quantum secure**, the empty "Nothing" slot appears, and **Turn on ML-KEM** shows the line for your server. Revert brings the live result back. ## For agents The Tamperbox MCP server exposes the same live check as `post_quantum_checker`, and `post_quantum_analyze` for pasted evidence. Search the catalog, inspect the schema and call it with the host name. Keep these warnings with any conclusion: - Two connections from one location at one moment; a browser's offer can differ from the probe's. - `supported: null` means "not shown", never "not supported". - Certificate signatures are not assessed. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/). ## Limits - Port 443 only, one location, one moment; other edges behind the same name can differ. - The default handshake uses OpenSSL's offer, not a browser ClientHello. - A failed ML-KEM-only handshake does not prove lack of support. - Pure ML-KEM groups are classified but not probed. - Pasted output is reported as supplied. - History is a browser interaction record, not server monitoring. Explicit tool links use temporary browser storage as described in [Browser transfers](#browser-transfers). ## References - [RFC 9846, The Transport Layer Security (TLS) Protocol Version 1.3](https://www.rfc-editor.org/rfc/rfc9846). Proposed Standard; obsoletes RFC 8446. Sections used: [2](https://www.rfc-editor.org/rfc/rfc9846#section-2), [2.1](https://www.rfc-editor.org/rfc/rfc9846#section-2.1), [4.3.7](https://www.rfc-editor.org/rfc/rfc9846#section-4.3.7), [4.3.8](https://www.rfc-editor.org/rfc/rfc9846#section-4.3.8). - [RFC 10024, Post-Quantum Traditional Hybrid Key Agreement Mechanisms for TLS 1.3](https://www.rfc-editor.org/rfc/rfc10024). Proposed Standard, August 2026; obsoletes the Kyber draft codepoints. Sections used: [4](https://www.rfc-editor.org/rfc/rfc10024#section-4), [4.3](https://www.rfc-editor.org/rfc/rfc10024#section-4.3), [7](https://www.rfc-editor.org/rfc/rfc10024#section-7), [7.1](https://www.rfc-editor.org/rfc/rfc10024#section-7.1), [7.4](https://www.rfc-editor.org/rfc/rfc10024#section-7.4). - [RFC 9954, Hybrid Key Exchange in TLS 1.3](https://www.rfc-editor.org/rfc/rfc9954). Informational, July 2026. Sections used: [3.1](https://www.rfc-editor.org/rfc/rfc9954#section-3.1), [3.2](https://www.rfc-editor.org/rfc/rfc9954#section-3.2). - [FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard](https://csrc.nist.gov/pubs/fips/203/final). NIST, August 2024. - [draft-ietf-tls-mlkem, ML-KEM for TLS 1.3](https://datatracker.ietf.org/doc/draft-ietf-tls-mlkem/). Internet-Draft, not yet published; cited for the pure ML-KEM names. - [IANA TLS Supported Groups registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8). --- # Postman Collection Converter What the converter reads from a Postman collection, an OpenAPI document or cURL commands, every rule it applies when it rewrites them, what each conversion note means, and how to fix and verify the export. Canonical: https://docs.tamperbox.dev/tools/postman-converter/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: A Postman Collection v2.0 or v2.1 export, an OpenAPI 3.0 or 3.1 document in JSON or YAML, or one or more cURL commands, pasted or opened as a file; Optionally a Postman environment export whose enabled values fill collection variables Outputs: OpenAPI 3.0.3 or 3.1.0 (JSON or YAML), a Postman Collection v2.1, or cURL commands, with a conversion report, request previews and a Copy or Download of the full output Limitations: Conversion can lose features the target cannot carry; scripts, external references and files are never read or executed; Credential replacement matches known field names only; custom fields, descriptions and scripts can still hold secrets; No request is ever sent; a syntactically valid export can still need credentials, server values or unsupported behaviour filled in The tool page is [tamperbox.dev/postman-converter](https://tamperbox.dev/postman-converter). It opens on a synthetic inventory collection, converts it to OpenAPI, and shows the report of what the conversion kept and what to check. This page is the long version: what each input form is read as, every rule applied when it is rewritten, what each conversion note means, and how to fix and verify an export. <div class="tb-callout"><strong>Where processing happens:</strong> everything runs in your browser. Inputs of 20,000 characters or more are converted in a background worker in the same tab. cURL text is tokenised, never run; nothing a document references (external <code>$ref</code> targets, <code>@file</code> bodies, cookie or header files) is fetched or read. No request is sent to any server, and nothing you enter is stored.</div> ## What the tool answers Four questions, in the order the page answers them: 1. **What is this?** Which format and version the input is, decided from its content unless you override it. 2. **What did the conversion keep?** How many requests, how many with authentication, how many saved response examples, and whether any known credential field was found. 3. **What needs checking?** Each conversion note names a feature the target format cannot carry, a value left unresolved, or an authentication setting that needs manual configuration. 4. **What does the output look like?** A request-by-request preview with credentials masked, and the full output to copy or download. The verdict sentence states the request count and the number of notes. A conversion that cannot complete says "Not converted." with the exact refusal, and nothing else is shown. ## Inputs ### A Postman collection A collection export needs an `info` object and an `item` array. If `info.schema` is present it must name Collection v2.0.0 or v2.1.0; a v1 export is refused with "Only Postman Collection v2.0 and v2.1 are supported." and must be upgraded in Postman first. Folders are walked recursively to 40 levels; deeper nesting is refused as "Too many nested folders." Disabled headers, query parameters, form fields and variables are skipped. An optional environment export, pasted into the Environment JSON field or opened as a file, must be a document with a `values` array. Its enabled values override collection values. An environment with no collection shows "Environment loaded. Add a Postman collection to use its values."; one supplied beside OpenAPI or cURL input is refused with "Environment values apply to Postman input. Clear the environment for OpenAPI or cURL." A pasted document that has a `values` array and neither `item` nor `openapi` is loaded as the environment, not as the source. ### An OpenAPI document JSON or YAML with an `openapi` value starting `3.0` or `3.1`, plus `info` and `paths` objects. Anything else is refused: "Supported OpenAPI versions are 3.0 and 3.1 (JSON or YAML)." or "OpenAPI needs info and paths objects." A Swagger 2.0 file has no `openapi` field, so it is read as a Postman collection and refused for lacking `info` and `item`. YAML is read with the JSON schema only (no custom tags), with at most 100 aliases; a circular alias is refused. ### cURL commands Text that starts with `curl`, after optional `#` comment lines, is read as cURL. Several commands are allowed, one per line, each beginning with `curl`; a backslash before a line break continues the command. Single quotes, double quotes and backslash escapes follow POSIX rules. The tokenizer is not a shell: `$`, backticks and the operators `; | & < > ( )` outside single quotes are refused rather than interpreted, with "Shell expansion is not supported. Use literal values in single quotes." or "Shell operators and expansions are not supported. Quote URLs and use one cURL command per line." ### Format detection and the override With "Read the source as" on Detect automatically, the page reads cURL when the text starts with `curl`, otherwise JSON or YAML; a document with an `openapi` field is OpenAPI and everything else is treated as Postman. The status line under the field then names what it found, such as "Postman Collection 2.1.0 · 1,577 characters". Choosing Postman, OpenAPI or cURL explicitly makes the page parse the text as that format and report "Could not convert this as OpenAPI: …" when it does not fit. A freshly pasted input whose chosen target repeats its own format is converted to the usual next format instead (Postman to OpenAPI JSON, OpenAPI to Postman, cURL to Postman), and the notice says so. ### Paste, files and the handoff Pasting into an empty or fully selected field, or anywhere on the page outside a control, replaces the source and starts fresh; pasting into part of the text edits in place. A dropped or opened file is read as text in the browser; one larger than 1 MB (1,000,000 bytes) is refused by name. A value arriving from another tool page through the one-use handoff is loaded the same way as a paste. Nothing is put in the URL. ### Limits and refusals | Limit | Value | Message | | --- | --- | --- | | Source length | 1,000,000 characters | Input is limited to 1,000,000 characters. | | Environment length | 1,000,000 characters | Environment is limited to 1,000,000 characters. | | File size | 1,000,000 bytes each | *name* is larger than 1 MB (1,000,000 bytes). | | Requests per conversion | 1,000 | Use at most 1,000 requests per conversion. | | Nesting | 80 levels, 100,000 nodes | Document is too complex. Use a smaller input. | | Integers | within the safe range (2<sup>53</sup> − 1) | A number is too large to convert without losing precision. Quote it as a string. | | Empty input | at least one request | No HTTP requests found in this input. | ## Reading the result ### Verdict and chips "Converted *n* requests." followed, when there are notes, by "*n* notes to check." The line under it names the direction, for example "Postman Collection → OpenAPI JSON". The status line under the source names the detected format, version and size, and the environment value count or file name when one applies. ### Findings The conversion report is the finding list. Its first four lines are fixed: requests kept, authenticated requests kept, response examples kept or omitted, and the credential check. Each conversion note follows as a Check line; the [finding reference](#finding-reference) lists every note the code can write. Notes are deduplicated, so a problem repeated across requests appears once unless the note names the request. ### Request preview One row per request: method, URL, folder path and name, the header count, the body mode, the authentication type and the number of saved responses. Opening a row shows the headers, authentication, path variables and body as the converter saw them. Known credential values are always masked in the preview, whatever the Replace credentials setting. Find a request filters the preview by name, URL, folder or method; Copy and Download always include every request. ### Output, Copy and Download The output field shows the result up to 150,000 characters and says when it is cut; Copy and Download always carry the complete output under the file name shown (`<slug>.openapi.json`, `.openapi.yaml`, `.postman_collection.json` or `.sh`). Reverse conversion loads the output as the new source and converts it back, so you can compare the round trip with the original. ### History Every Break it case, Heal it repair and Reverse conversion is logged with what it replaced. Revert undoes the newest change; Reset input returns to the source exactly as pasted. A new typed or pasted source starts a new log, and History keeps up to 50 entries. ### Take it further Links that carry a value derived from the converted requests into another tool in the same category: a CORS preflight for the first request, and the redirect chain and HTTP/3 support at the first request's server. Each opens the other tool with that value in its box and nothing in the URL. The links are hidden while the source is the synthetic example, because its reserved `api.example.com` host is never probed. ## Method ### Parsing and safety checks 1. The source is trimmed; an empty source is refused with "Paste a collection, OpenAPI document, or cURL command." 2. Text starting with `{` must parse as strict JSON before the YAML reader runs, so a JSON file with a trailing comma is refused as "Cannot read JSON/YAML: …" rather than silently tolerated. 3. The parsed tree is walked once. Nesting past 80 levels or more than 100,000 nodes, a non-finite number, an integer outside the safe range, or a circular YAML alias stops the conversion with the message in the limits table. 4. The root must be an object: "Expected a Postman collection or OpenAPI document." ### Postman collections - Variables resolve from collection, folder and request scopes, then the environment, then the request's URL variables. A `{{name}}` whose value contains another placeholder is expanded up to eight times. Names still unresolved are listed in one "Unresolved variables: …" note and added as empty variables to Postman output, with the description "Set locally before sending requests." - `:name` path variables stay editable for Postman and OpenAPI output. For cURL output a known value is substituted, URL-encoded. - A request given as a plain string is read as GET to that URL. A missing URL is refused: "A request is missing its URL." - Bodies: `raw` converts, with `application/json` when the editor language is JSON and `text/plain` otherwise; `urlencoded` and `formdata` convert field by field. Any other mode, such as GraphQL or a binary file, writes "Body mode *mode* is not converted (*request*)." A disabled body is dropped. - Authentication is inherited from the folder or collection when a request has none. - Scripts: a collection-level `event` writes "Postman scripts and tests are not converted or executed."; each folder or request with events writes "*Folder / Request*: *n* script/test event(s) omitted; scripts never execute here." ### OpenAPI documents - Every path starting with `/` yields one request per `get`, `post`, `put`, `patch`, `delete`, `head`, `options` and `trace` operation; the first tag becomes its folder. A path item given by reference is resolved first. - Servers: the operation's, then the path item's, then the document's; only the first is used, and a second writes "Only the first server for each operation is used." `{variable}` defaults are filled in. A relative or missing server becomes `{{baseUrl}}` with the note "Relative server URLs use the `{{baseUrl}}` placeholder." - Parameter examples come from `example`, then the first of `examples`, then the schema: `example`, `examples[0]`, `default`, the first `enum` value, the first `oneOf` or `anyOf` branch, merged `allOf`, `minimum` or 0 for numbers, `false` for booleans, `"string"` otherwise; `readOnly` properties are left out. Generation stops after 20 levels: "Schema is recursive or too deep to generate an example. Add an explicit example." - Query parameters are serialised in `form` style (exploded by default) and `deepObject`; any other style writes "*request*: query style *style* is simplified for *name*." Header and cookie parameters become headers; a complex non-query value writes "*request*: complex *in* parameter *name* is simplified; review its serialization." #### Security, bodies, responses and references - Security: only the first alternative is used (note when more exist), and combined requirements get a note. Bearer becomes bearer auth with `{{token}}`, Basic becomes `{{username}}` and `{{password}}`, an API key in a header or query becomes API key auth with `{{apiKey}}` (a cookie key becomes a Cookie header), OAuth 2.0 imports the first flow's URLs with `{{accessToken}}`, `{{clientId}}` and `{{clientSecret}}` and the note "obtain a token in Postman before sending." Any other scheme writes "needs manual configuration." - Request bodies: the first media type only (note when more exist); form media types become fields, `binary` properties become file fields; other types become a raw body with a Content-Type header. - Responses become saved examples. `default` maps to 200 and a range such as `4XX` to 400, each with a note; an example given by reference whose value is absent writes "external response example *name* is not fetched." - References: only local `#/` pointers resolve, with `~0` and `~1` unescaped. An external one stops with "External reference *ref* is not fetched. Bundle it into the document first."; a missing target with "Reference *ref* was not found."; a cycle with "Circular reference *ref* cannot be expanded into an example." ### cURL options | Option | Read as | Note | | --- | --- | --- | | `-X`, `--request`, `-I`, `--head` | the method (HEAD for `-I`) | explicit; data no longer switches it to POST | | `-H`, `--header` | a `Name: value` header | `@file` header files refused | | `-d`, `--data`, `--data-raw`, `--data-binary`, `--data-urlencode`, `--json` | body data, joined with `&` | `@file` refused except after `--data-raw`; `--json` adds JSON Content-Type and Accept | | `-F`, `--form`, `--form-string` | a multipart text field | `@file` and `<file` fields refused; data and form cannot be combined | | `-u`, `--user` | Basic authentication | split at the first colon | | `-b`, `--cookie` | a Cookie header | must contain `=`; cookie files refused | | `--url`, bare argument | the URL | one per command | | `-G`, `--get` | data appended to the query string | method stays GET | | `-L`, `-s`, `-S`, `--compressed` | accepted, not kept | "cURL transport option *flag* is not retained." | | `-g`, `--globoff` | accepted silently | the output always uses it | | anything else | refused | "Unsupported cURL option *flag*. Remove it before converting." | Inline forms (`-XPOST`, `--header=…`) are split first. Data without `-X` makes the request a POST with `application/x-www-form-urlencoded` unless a header sets the type; form fields make it a POST with a multipart body. ### What each output keeps or drops | Target | Keeps | Drops or changes | | --- | --- | --- | | Postman Collection v2.1 | folders, query parameters split out, path variables, bodies with the JSON language flag, saved responses with their original request | an `Authorization: Bearer` header becomes bearer auth; Editable base URL variables replaces each origin with `{{baseUrl}}` variables | | OpenAPI 3.0.3 or 3.1.0 | one operation per method and path, path and query parameters with examples, headers as parameters, security schemes, request body examples, response examples when Include response examples is on | Authorization values and Basic credentials omitted; repeated query parameters, headers and form fields keep one example; a body that is not valid JSON stays a literal string | | cURL | `--globoff`, `--request`, `--url`, headers, `--user`, `--data-raw`, `--data-urlencode`, `--form-string` | saved responses ("Saved response examples are not included in cURL."); file fields ("File field *name* omitted: select the file in your client.") | For OpenAPI, a request whose URL does not start with `http://`, `https://` or `{{baseUrl}}` stops the conversion, as does a second request with the same method and path: "Duplicate *METHOD* */path*: OpenAPI allows one operation per method/path. Rename or remove the duplicate request." Every OpenAPI export ends with the note "Generated OpenAPI is a starting point: add response schemas, validation rules, and descriptions before publishing." When an OpenAPI or Postman source is converted to its own format with no option changed, the document is passed through unchanged and the notes are cleared. ### Credential replacement "Replace credentials" is on by default. The masker matches field names, case-insensitively and ignoring hyphens and spaces, against a fixed list: `authorization`, `proxy_authorization`, `cookie`, `set_cookie`, `password`, `passwd`, `pwd`, `secret`, `client_secret`, `access_token`, `refresh_token`, `token`, `api_key`, `x_api_key`, `x_auth_token`, `private_key`, `session`, `sessionid`, `access_key`, `secret_key`, `secretaccesskey`, `aws_secret_access_key` and `aws_access_key_id`. It looks in headers (the token after `Bearer` or `Basic` in an Authorization header), URL user info and query strings, JSON and URL-encoded bodies, form fields, auth settings, collection and environment variables (any variable of type `secret` too) and saved response headers and bodies. Each distinct value becomes a `{{redacted_<field>}}` placeholder and an empty collection variable; a value that is already a `{{placeholder}}` is left alone. Switched off, the same fields are counted and reported for review while Copy and Download keep the originals. The request preview masks known values either way. ## Standards and conformance ### OpenAPI 3.0.3 and 3.1.0 The reader and writer follow the [OpenAPI Specification 3.0.3](https://spec.openapis.org/oas/v3.0.3.html) and [3.1.0](https://spec.openapis.org/oas/v3.1.0.html). The [Paths Object](https://spec.openapis.org/oas/v3.0.3.html#paths-object) requires that each field name "MUST begin with a forward slash (/)", which is why paths without one are skipped. A [Path Item Object](https://spec.openapis.org/oas/v3.0.3.html#path-item-object) has one field per HTTP method, so a second request with the same method and path has nowhere to go; the converter stops rather than drop one. The [Reference Object](https://spec.openapis.org/oas/v3.0.3.html#reference-object) field `$ref` is "REQUIRED. The reference string."; the tool resolves only local JSON pointers. Servers follow the [Server Object](https://spec.openapis.org/oas/v3.0.3.html#server-object) and [Server Variable Object](https://spec.openapis.org/oas/v3.0.3.html#server-variable-object) defaults; security the [Security Scheme Object](https://spec.openapis.org/oas/v3.0.3.html#security-scheme-object) types `http`, `apiKey` and `oauth2`; bodies and responses the [Request Body Object](https://spec.openapis.org/oas/v3.0.3.html#request-body-object), [Media Type Object](https://spec.openapis.org/oas/v3.0.3.html#media-type-object) and [Responses Object](https://spec.openapis.org/oas/v3.0.3.html#responses-object). Query serialisation follows the [Parameter Object](https://spec.openapis.org/oas/v3.0.3.html#parameter-object) `style` and `explode` rules for `form` and `deepObject` only. Written documents carry `openapi: 3.0.3` or `3.1.0`, `operationId` values `request_1`, `request_2` and so on (the specification requires each to be unique among all operations), and schemas of type `string` for every parameter. ### Postman Collection v2.1 Input is read against the shape of the [Postman Collection Format v2.1.0 schema](https://schema.postman.com/collection/json/v2.1.0/draft-07/collection.json): `info`, `item`, `variable`, `auth`, `event`, `request` with `url`, `header`, `body` and `auth`, and `response`. Output declares `info.schema` as `https://schema.getpostman.com/json/collection/v2.1.0/collection.json`, the identifier Postman itself writes. Variable scoping (collection, folder, request, environment) follows Postman's documented precedence; the eight-level expansion limit is the tool's own. ### curl cURL input follows the [curl manual](https://curl.se/docs/manpage.html) for the options the table above lists, each linked at its entry: [`-X`](https://curl.se/docs/manpage.html#-X), [`-H`](https://curl.se/docs/manpage.html#-H), [`-d`](https://curl.se/docs/manpage.html#-d), [`--data-raw`](https://curl.se/docs/manpage.html#--data-raw), [`--data-urlencode`](https://curl.se/docs/manpage.html#--data-urlencode), [`--json`](https://curl.se/docs/manpage.html#--json), [`-F`](https://curl.se/docs/manpage.html#-F), [`--form-string`](https://curl.se/docs/manpage.html#--form-string), [`-u`](https://curl.se/docs/manpage.html#-u), [`-b`](https://curl.se/docs/manpage.html#-b), [`--url`](https://curl.se/docs/manpage.html#--url), [`-G`](https://curl.se/docs/manpage.html#-G), [`-I`](https://curl.se/docs/manpage.html#-I) and [`--globoff`](https://curl.se/docs/manpage.html#--globoff). The manual describes `-d` data as sent "in the same way that a browser does when a user has filled in an HTML form", which is why data makes the method POST with `application/x-www-form-urlencoded` unless told otherwise. Quoting follows POSIX shell rules for single quotes, double quotes and backslashes; expansion and operators are deliberately not implemented. ### HTTP, URI and authentication RFCs - Methods and headers follow [RFC 9110, section 9](https://www.rfc-editor.org/rfc/rfc9110#section-9) (methods) and [section 5](https://www.rfc-editor.org/rfc/rfc9110#section-5) (fields): header names must not contain line breaks, colons or NUL, and values must not contain line breaks; a method must be uppercase letters. - URLs must be absolute `http` or `https` URIs in the sense of [RFC 3986, section 4.3](https://www.rfc-editor.org/rfc/rfc3986#section-4.3), or begin with `{{baseUrl}}`; query values are percent-encoded per [section 2.1](https://www.rfc-editor.org/rfc/rfc3986#section-2.1), with `{{placeholders}}` restored. - `-u` produces the Basic scheme of [RFC 7617, section 2](https://www.rfc-editor.org/rfc/rfc7617#section-2): user-id and password separated by the first colon. - `Authorization: Bearer` headers are recognised per [RFC 6750, section 2.1](https://www.rfc-editor.org/rfc/rfc6750#section-2.1) and turned into bearer auth or a `bearerAuth` security scheme. - `-b name=value` writes a Cookie header in the form of [RFC 6265, section 4.2](https://www.rfc-editor.org/rfc/rfc6265#section-4.2); cookie files are not read. - `-F` fields are described as `multipart/form-data` per [RFC 7578, section 4](https://www.rfc-editor.org/rfc/rfc7578#section-4); the tool does not build the multipart body itself, it describes the fields for the target client. - JSON is parsed strictly per [RFC 8259](https://www.rfc-editor.org/rfc/rfc8259); YAML is read with the JSON schema, the subset [RFC 9512, section 3](https://www.rfc-editor.org/rfc/rfc9512#section-3) describes as interoperable with JSON. ### Where the tool stops It does not validate documents against the full OpenAPI or Postman JSON schemas; it reads the fields it needs and refuses what it cannot read. It does not build request bodies, resolve `@file` references, follow external references, run scripts, or send any request. Schema constraints, links, callbacks and alternate media types are noted, not carried. Equivalence between the input and the output is not claimed: the report lists what moved, and the round trip is there to check the rest. ## Finding reference ### Report lines | Line | Status | Meaning | What to do | | --- | --- | --- | --- | | *n* requests | Kept | Methods, URLs, headers and supported bodies parsed. | Compare with the request count in your client. | | *n* authenticated requests | Kept | Supported authentication is included (OpenAPI: described with security schemes). | Configure credentials in the client; placeholders carry none. | | *n* response examples | Kept or Omitted | Included where the target supports them; omitted for cURL or when Include response examples is off. | Keep the original collection if the examples matter. | | *n* credential fields replaced | Checked | Known credential fields use `{{redacted_*}}` placeholders. | Review custom text and scripts the name list cannot see. | | *n* credential fields detected | Check | Replace credentials is off; the output can contain original credentials. | Turn replacement on before sharing, or scrub by hand. | | No known credentials found | Checked | No field name on the list matched. | Not proof that the export holds no secret. | ### Notes about the source | Note | Cause | What to do | | --- | --- | --- | | Unresolved variables: … | `{{names}}` with no value in any scope or the environment | Fill variables under Heal it, or set them in the client | | Path variables remain editable. | A `/:name` segment in a URL | Set the values before sending | | Body mode *mode* is not converted (*request*). | GraphQL, binary or another unsupported Postman body mode | Rebuild the body in the client | | Postman scripts and tests are not converted or executed. | A collection-level `event` | Port scripts by hand | | *path*: *n* script/test event(s) omitted; scripts never execute here. | Events on a folder or request | Same | | Only the first server for each operation is used. | Several `servers` entries | Add the others as variables in the client | | Relative server URLs use the `{{baseUrl}}` placeholder. | A server URL without a scheme | Set `baseUrl` | | *request*: query style *style* is simplified for *name*. | A style other than `form` or `deepObject` | Check the serialised query | | *request*: complex *in* parameter *name* is simplified; review its serialization. | An object or array example outside the query | Check the header or path value | | *request*: response *code* uses *n* for its Postman example. | `default` or a range such as `4XX` | Expect 200 or 400 in the saved example | | *request*: external response example *name* is not fetched. | An example whose value is a reference without content | Inline the example | | cURL transport option *flag* is not retained. | `-L`, `-s`, `-S` or `--compressed` | Re-add it in the client if needed | ### Notes about authentication and output | Note | Cause | What to do | | --- | --- | --- | | *request*: only the first authentication alternative is used. | Several entries in `security` | Choose the alternative the client should use | | *request*: combined authentication requirements need review in the destination client. | One requirement naming several schemes | Configure both | | *request*: OAuth 2.0 settings imported; obtain a token in Postman before sending. | An `oauth2` scheme | Run the flow in the client | | *request*: authentication scheme *name* needs manual configuration. | `openIdConnect`, an unknown `http` scheme or a cookie API key with other requirements | Configure by hand | | Authentication *type* needs manual configuration (*request*). | A Postman auth type the writer cannot express | Same | | *request*: the current OAuth access token is used; token acquisition needs manual setup. | OAuth 2.0 auth written to cURL or OpenAPI headers | Replace `{{accessToken}}` | ### Notes about the output | Note | Cause | What to do | | --- | --- | --- | | Authorization values are omitted from OpenAPI. Configure credentials in your client. | An Authorization header on OpenAPI output | Expected | | OpenAPI describes authentication; Basic credentials are omitted. | Basic auth on OpenAPI output | Expected | | Only the first request body media type is used. | Several media types under `content` | Add the others by hand | | Repeated query parameter, header or form field *name* uses its first (or last) example in OpenAPI. | Duplicates of one name | One example survives | | Body cannot be represented safely as JSON (*request*); retained as a literal string example. | A JSON Content-Type with a body that does not parse | Fix the body or the type | | Saved response examples are not included in cURL. | Responses on cURL output | Keep the collection | | File field *name* omitted: select the file in your client. | A file form field on cURL output | Expected | | OpenAPI schema constraints, links, callbacks, and alternate request media types are not carried into runnable requests. | Any OpenAPI source | Expected | | Generated OpenAPI is a starting point: add response schemas, validation rules, and descriptions before publishing. | Any OpenAPI output | Expected | ### Refusals A refusal stops the conversion and shows one message with the verdict "Not converted." The messages come from the limits table, the input sections above, and these: "Expected Postman info and item fields.", "Only Postman Collection v2.0 and v2.1 are supported.", "Too many nested folders.", "Collection item is missing a request.", "A request is missing its URL.", "Expected a Postman environment export with a values array.", "Invalid HTTP method (*request*).", "Use an HTTP(S) URL or `{{baseUrl}}` (*request*).", "URLs and headers cannot contain line breaks or invalid header names.", "OpenAPI 3.0 cannot represent method *METHOD*.", "URL must start with http://, https://, or `{{baseUrl}}` (*request*).", the duplicate operation message, and for cURL: "Every command must start with curl.", "Missing value for *flag*.", "Headers must use Name: value.", "Use --data-urlencode name=value.", "Form fields must use name=value.", "Use separate cURL commands for multiple URLs.", "cURL command is missing a URL.", "A request cannot combine data and multipart form options.", "Incomplete shell escape." and "Unclosed quote in cURL input." ## Guide ### Duplicate operation in OpenAPI Two requests with the same method and path cannot both exist in an OpenAPI document. Rename the path of one (a different `:id` example is not enough; the templated path is what counts), remove it, or press Drop duplicates under Heal it, which keeps the first request for each method and path and lists what it removed. Confirm by converting again: the verdict should name one request fewer and no duplicate refusal. ### Unresolved variables A `{{name}}` with no value stays a placeholder and is listed once. Either add the value to the collection or environment before converting, or press Fill variables under Heal it, enter values, and apply: for a Postman source the values are written as collection variables, for cURL they are substituted in place. Values stay in this tab. A filled credential still shows as `{{redacted_*}}` while Replace credentials is on. ### Unsupported body mode GraphQL and file bodies have no equivalent in the writer. Convert the request anyway, then rebuild the body in the target client. For GraphQL, a raw JSON body with `query` and `variables` keys converts cleanly, so one option is to switch the body mode in Postman before exporting. ### External reference `$ref` targets outside the document are never fetched. Bundle the document first (most OpenAPI tooling has a bundle or dereference command) so every reference is a local `#/` pointer, then convert again. A circular reference cannot produce an example; give the schema an explicit `example` to break the cycle. ### Unsupported cURL option The converter refuses rather than guesses. Remove the option, or replace it with a supported one: `--data-raw` for data that starts with `@`, `-H 'Cookie: name=value'` for a cookie file, a text field for a file upload. Transport options (`-L`, `-s`, `--compressed`) can simply be dropped; the target client sets them itself. ### Credentials detected With Replace credentials off, the report says how many known fields were found and that the output carries them. Turn replacement on, or remove the values at the source, before sharing an export. Replacement is name-based: a secret in a description, a custom header named for a project, or a script is not seen. Read the output once before it leaves your machine. ### Break it cases | Case | What it does | What to look at | | --- | --- | --- | | Duplicate operation | Copies the first request of your Postman source next to itself (or loads the example when the source cannot carry it) and targets OpenAPI JSON | The duplicate refusal; Drop duplicates under Heal it | | Unresolved variable | Appends `/{{productId}}` to the first request's URL in your source, or to a cURL command | The "Unresolved variables" note; Fill variables | | Malformed input | Cuts the last brace or bracket off your JSON source, or off the example | "Cannot read JSON/YAML"; Repair syntax | Each case builds on the source in the box, logs what it replaced, and can be undone. ### Heal it repairs Repair syntax closes open brackets and strings and drops dangling commas, outside strings only, and offers itself only when the result parses; what was cut off stays missing. Drop duplicates keeps the first request per method and path. Fill variables writes values for every unresolved name. Each repair goes through the source field, so Undo and History apply, and success is claimed only once the repaired source converts. ### Independent check Import the download into the target client and compare its request list with the report's count. For OpenAPI, run a validator over the file: ```sh npx @redocly/cli lint inventory-api.openapi.json ``` For cURL, run one command with `--verbose` against a test server you control and compare the method, headers and body with the preview. For Postman, Import, Files, then open the first request and confirm the variables resolve. ## Worked example The opening source is a synthetic Inventory API collection: a `baseUrl` variable set to `https://api.example.com/v1`, collection-level bearer auth with `{{token}}`, and a Products folder with two requests. List products is a GET to `{{baseUrl}}/products?limit=20` with an Accept header and one saved 200 response; Create product is a POST with a raw JSON body. The host is a reserved documentation name, so nothing on the page could reach it even if a request were sent, and none is. Converted to OpenAPI JSON, the report reads 2 requests, 2 authenticated requests (both inherit the bearer auth), 1 response example and No known credentials found (`{{token}}` is already a placeholder). Three notes follow: Unresolved variables: token, because no scope gives `token` a value; Authorization values are omitted from OpenAPI; and the fixed note that generated OpenAPI is a starting point. The output has one `/products` path with `get` and `post` operations, a `limit` query parameter with example `20`, a `bearerAuth` security scheme, the saved response under `responses.200`, and the JSON body as a request example. Switch the target to cURL and the report adds that saved responses are not included; switch to Postman and the document is passed through unchanged, with the notes cleared. Press Duplicate operation: the second Create product makes the OpenAPI conversion stop, Drop duplicates restores it. Press Malformed input: the cut-off collection fails to parse, Repair syntax closes it. Reverse conversion turns the OpenAPI output back into a collection, which is the quickest way to see what the round trip kept. ## For agents The Tamperbox MCP server exposes two MCP tools: use `search` to inspect the catalog and schema, then use `execute` to call an operation through `tamperbox.request`. The converter maps to two `POST /v1/tools/...` operations: | Operation | Required input | Result | | --- | --- | --- | | `api_convert` | A JSON, YAML or text artifact plus `options.target` | An output artifact in Postman, OpenAPI JSON, OpenAPI YAML or cURL form, with warnings and provenance | | `api_convert_report` | `input`; optional `target`, source hint and conversion options | Converted text, filename, detected source format, conversion report, request previews and warnings | `api_convert_report` is the detailed choice when an agent needs Postman environment input, response inclusion, server parameterisation or a named output. Neither operation executes a request. Keep these warnings with any conclusion drawn from the result: - Conversion can lose features the target format cannot carry; the notes list what moved, not what the source meant. - Credential replacement is name-based and not exhaustive; an export is not proven free of secrets. - A converted document is a starting point: it may still need credentials, server values, schemas and unsupported behaviour filled in before it works. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, the [operation catalog](https://docs.tamperbox.dev/reference/operations/) for the transform family, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for what travels where: the browser page sends nothing, while an MCP call sends the document to the service. ## Limits - Everything runs in the browser; no request is sent, and nothing referenced by the input is read or fetched. - At most 1,000,000 characters of source, 1,000,000 of environment, 1,000 requests, 80 levels of nesting and 1 MB per file. - Postman v1 exports, Swagger 2.0, external references, scripts, shell expansion and file-backed data are refused or dropped, never guessed. - Only the first server, security alternative and request body media type are carried. - Credential replacement matches a fixed list of field names; custom text, descriptions and scripts are not inspected. - The output preview is cut at 150,000 characters; Copy and Download are complete. - Nothing you enter is stored or put in a URL. ## References - [OpenAPI Specification v3.0.3](https://spec.openapis.org/oas/v3.0.3.html), OpenAPI Initiative, February 2020. Sections used: Paths Object, Path Item Object, Operation Object, Parameter Object, Request Body Object, Media Type Object, Responses Object, Reference Object, Server Object, Server Variable Object, Security Scheme Object. - [OpenAPI Specification v3.1.0](https://spec.openapis.org/oas/v3.1.0.html), OpenAPI Initiative, February 2021. Read with the same rules; written when 3.1.0 is selected. - [Postman Collection Format v2.1.0, JSON schema](https://schema.postman.com/collection/json/v2.1.0/draft-07/collection.json). The shape read for input and declared in output. - [curl manual](https://curl.se/docs/manpage.html). Options read: `-X`, `-H`, `-d`, `--data-raw`, `--data-binary`, `--data-urlencode`, `--json`, `-F`, `--form-string`, `-u`, `-b`, `--url`, `-G`, `-I`, `-L`, `-s`, `-S`, `--compressed`, `-g`. - [RFC 9110, HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110). Internet Standard, STD 97. Sections used: [5](https://www.rfc-editor.org/rfc/rfc9110#section-5) and [9](https://www.rfc-editor.org/rfc/rfc9110#section-9). - [RFC 3986, Uniform Resource Identifier (URI): Generic Syntax](https://www.rfc-editor.org/rfc/rfc3986). Internet Standard, STD 66; updated by [RFC 7320](https://www.rfc-editor.org/rfc/rfc7320) and [RFC 8820](https://www.rfc-editor.org/rfc/rfc8820) (URI design ownership, not applied). Sections used: [2.1](https://www.rfc-editor.org/rfc/rfc3986#section-2.1) and [4.3](https://www.rfc-editor.org/rfc/rfc3986#section-4.3). - [RFC 7617, The 'Basic' HTTP Authentication Scheme](https://www.rfc-editor.org/rfc/rfc7617). Proposed Standard. Section used: [2](https://www.rfc-editor.org/rfc/rfc7617#section-2). - [RFC 6750, The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://www.rfc-editor.org/rfc/rfc6750). Proposed Standard; updated by [RFC 8996](https://www.rfc-editor.org/rfc/rfc8996) (TLS 1.0 and 1.1 deprecated) and [RFC 9700](https://www.rfc-editor.org/rfc/rfc9700) (OAuth 2.0 security best current practice), neither applied here. Section used: [2.1](https://www.rfc-editor.org/rfc/rfc6750#section-2.1). - [RFC 6265, HTTP State Management Mechanism](https://www.rfc-editor.org/rfc/rfc6265). Proposed Standard. Section used: [4.2](https://www.rfc-editor.org/rfc/rfc6265#section-4.2). - [RFC 7578, Returning Values from Forms: multipart/form-data](https://www.rfc-editor.org/rfc/rfc7578). Proposed Standard. Section used: [4](https://www.rfc-editor.org/rfc/rfc7578#section-4). - [RFC 8259, The JavaScript Object Notation (JSON) Data Interchange Format](https://www.rfc-editor.org/rfc/rfc8259). Internet Standard, STD 90. Applied as the strict parser for JSON input. - [RFC 9512, YAML Media Type](https://www.rfc-editor.org/rfc/rfc9512). Informational. Section used: [3](https://www.rfc-editor.org/rfc/rfc9512#section-3), the JSON-compatible subset. --- # Redirect Checker What the redirect checker requests, how it reads each hop, every rule it applies to a chain, what each finding means for visitors and crawlers, and how to fix and verify each one. Canonical: https://docs.tamperbox.dev/tools/redirect-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public HTTP or HTTPS address on port 80 or 443, or the output of curl -sIL to paste Outputs: A verdict naming where the chain lands and after how many hops, chips, the chain hop by hop with what changed and the time to the first byte of each, and findings worst first Limitations: Only HTTP redirects are followed, from one location at one moment, without cookies; a meta refresh or a script redirect inside a page is not seen The tool page is [tamperbox.dev/redirect-checker](https://tamperbox.dev/redirect-checker). It opens by tracing `tamperbox.dev` live from `http://`, answers in one sentence where the chain lands, and shows every hop under it. This page is the long version: what our server requests, every rule the page applies, what each finding means, and how to fix and verify each one. <div class="tb-callout"><strong>Where processing happens:</strong> a URL is sent to the Tamperbox server, which requests each hop itself, without cookies, and returns the status, Location and response headers of every answer. Pasted curl output is read in your browser and never uploaded. History and tool-to-tool transfers remain in the browser; see Browser transfers below.</div> ## What the tool answers Four questions, in the order a browser meets them: 1. **Where does this address end up?** The final status and address, after how many redirects. 2. **Does the chain ever stop?** A loop, a chain longer than 15 hops, a hop that does not answer, or a target our server refuses to request. 3. **Is each hop safe and final?** A drop from HTTPS to plain HTTP, and a permanent move served with a temporary code. 4. **What does the chain cost?** Two or more redirects before the page, hosts crossed, and the time each hop took from our server. The verdict sentence answers the first question and names the worst of the rest. The chips repeat the redirect count and every failure. Findings under the verdict list everything, worst first, with the passes folded into one line. ## Inputs ### A URL `example.com/old-page`, `http://example.com/old-page` or `https://www.example.com/`. The trace starts when you stop typing, or on Enter. An address without a scheme starts at `http://`, so the redirect to HTTPS is the first hop and is judged like any other. A scheme you type is kept. The page's parser (`parseUrl` in the site library) refuses, with a message in the field, an address with spaces, a scheme other than `http` or `https`, an IP address instead of a host name, a host without a top-level domain, a port other than 80 or 443, and a user name or password in the address. The last two offer a repair under Heal it ("Use the standard port", "Remove them"). The fragment (`#…`) is dropped before the request. Our server applies the same rules again to the input and to every redirect target, and additionally requires the host to resolve only to public addresses, so a chain cannot be used to reach a private network. ### Pasted curl output Paste the output of: ```sh curl -sIL http://example.com/old-page ``` The page recognises a paste that starts with a status line (`HTTP/1.1 301 Moved Permanently`, `HTTP/2 200`) or with a `Name: value` header line, and reads it in the browser. Each status line starts a new response; header lines belong to the response above them; an obsolete folded continuation line is joined to the header before it. The address of the first response is shown as "The address you requested"; the address of each later response is the previous response's Location, resolved against the previous address when it is relative. A block with no status line is ignored. There are no timings for pasted input, and the chain cannot be checked for private targets because nothing is requested. Pasted output has no timings, so the total line is hidden; the verdict says how many responses the paste contained. If the last response is still a redirect (curl was run without `-L`, or stopped early), the chain is reported as incomplete and does not claim a final address. ### Files A `.txt` file dropped on the field, or chosen with Open file, is read in the browser like a paste. Up to 512 KiB is read. ### What the page does to pasted text Before anything runs, pasted text goes through the shared cleaner. If the text is already an address the parser accepts, it is kept whole, including its path and query. If it is not, the cleaner tries the parts it holds: a quoted or bracketed link loses its quotes and trailing punctuation, an email address or `mailto:` link becomes its domain. Text that fits nothing stays exactly as pasted, so the parser's own message explains it. Typing is never rewritten; leaving the field or pressing Enter tidies what was typed the same way. Break it and Heal it loads are never cleaned. ## Reading the result ### Verdict and chips The first sentence names the outcome: "Lands on 200 OK after 2 redirects, at https://www.example.com/", "Ends on plain HTTP 200 OK", "Redirect loop", "Still redirecting after 15 hops.", "Ends at 404 Not Found", "example.com did not answer", "Stopped at a redirect to …, which is not a public address." or, for a cut paste, "Incomplete redirect chain:". The detail under it gives the request count and the summed time to the first byte, or the response count of a paste. The first chip is the redirect count (PASS for none or one, CHECK for two or more) and scrolls to the chain. The other chips repeat every failure and check from the findings. ### Findings Every rule that fired, worst first. Two or more passes fold into one "n checks passed" line. A chip names the same finding as the row it points at. ### Chain One row per hop: the status code with its class colour, the hop number, the address with the part that changed from the previous hop marked, labels for what changed ("to HTTPS", "adds www", "drops trailing slash", "new path"), the Location header, the Server header where sent, Cache-Control on redirect hops, and the response headers behind a disclosure. The last row is marked as the final page or, in a loop, as the hop that closed the loop. A hop that failed carries its error message. The bar on the right is each hop's time to the first byte, drawn against the slowest hop. Under the list, for a live chain of two or more requests, the total: how many requests, each from a fresh connection, and the summed time. ### History Every Break it and Heal it change, newest first, with what it replaced. Revert undoes the newest change; Reset input returns to what you entered. ### Take it further Follow-up links appear only for a completed live trace whose final status is below 400 and whose final address differs from the input. The [HTTP/3 & Compression Checker](https://docs.tamperbox.dev/tools/http3-checker/) receives that final address. The [CORS Tester](https://docs.tamperbox.dev/tools/cors-tester/) link additionally requires an HTTPS destination; it fills the URL field, and you choose the request settings and run the check there. Pasted, interrupted, looping and failed traces do not offer these links. ### Browser transfers Explicit tool links temporarily place the transferred input in browser `sessionStorage`. The URL fragment carries a random token, not the input. The receiving page accepts that token once, for its destination path and for less than one minute, then removes it from the address. A same-origin browser channel can complete a transfer into another tab. Ordinary documentation links do not transfer input. When browser storage is unavailable, navigation still works but the input may need to be pasted again. ## Method The rules, in the order they are applied. The chain analysis is one function, `analyzeChain` in the shared HTTP checks library, that the page, the server and the MCP operation run on the same evidence. ### How each hop is requested Our server sends one GET per address with automatic redirect following turned off, a stable user agent (`Mozilla/5.0 (compatible; TamperboxBot/1.0; +https://tamperbox.dev/bot)`), `Accept: */*` and `Accept-Encoding: identity`. No cookies are sent on any hop, and the request headers are the same on every hop. The body is not read beyond what finishes the response. For each answer the server records the status code, the raw Location header, the response headers in received order, and the time from the start of the request to the end of its headers. Cookie and authentication headers (`Set-Cookie`, `WWW-Authenticate`, `Proxy-Authenticate`, `Authentication-Info`) are left out of the evidence; header values are cut at 2,048 characters and at most 100 headers are kept per hop. A status of 301, 302, 303, 307 or 308 is a redirect, following [RFC 9110 Section 15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4). The Location value is resolved against the address just requested, as [RFC 9110 Section 10.2.2](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.2) describes: "When it has the form of a relative reference [...], the final value is computed by resolving it against the target URI". The resolved address is validated again before it is requested. ### What stops a chain | Stop | Condition | Verdict | | --- | --- | --- | | `final` | The answer is not a redirect | Where it lands, or the error status | | `loop` | The next address is one already requested; that hop is appended once more to show the closing of the loop | "Redirect loop" | | `limit` | 15 answers, the last still a redirect | "Still redirecting after 15 hops." | | `error` | DNS, connection, TLS, HTTP or timeout failure, or a redirect without a Location header | "… did not answer" | | `unsafe` | The next target fails validation: private or reserved address, a port other than 80 or 443, credentials, a non-HTTP scheme | "Stopped at a redirect to …" | A redirect without Location ends the chain with the error `missing_location` on that hop: there is nowhere to go next. ### What changed on each hop Each hop is compared with the previous address and labelled: `to HTTPS` or `to plain HTTP` for a scheme change; `adds www`, `drops www` or `to <host>` for a host change; `port <n>` for a port change; `adds trailing slash`, `drops trailing slash`, `changes case` or `new path` for a path change; `adds a query`, `drops the query` or `changes the query`. The label decides two findings: - **Drops from HTTPS to plain HTTP** (FAIL): any hop labelled `to plain HTTP`. Everything after that hop, including later redirects, travels in clear text and can be read or altered on the network. This is the tool's own rule; RFC 9110 permits the redirect. - **Final address uses plain HTTP** (CHECK): a completed chain whose final page is on `http:` even without a downgrade hop, for example an address that never redirected to HTTPS. The page adds this finding; a final error status takes precedence in the headline. ### Permanent moves with temporary codes [RFC 9110 Section 15.4.2](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.2) defines 301: "the target resource has been assigned a new permanent URI and any future references to this resource ought to use one of the enclosed URIs". [Section 15.4.3](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.3) defines 302 as temporary: "Since the redirection might be altered on occasion, the client ought to continue to use the target URI for future requests." A temporary code on a permanent move therefore tells clients and search engines to keep the old address. The tool flags a 302, 303 or 307 only when the move it makes is canonical by nature: every label on the next hop is one of `to HTTPS`, `adds www`, `drops www`, `adds trailing slash` or `drops trailing slash`. A temporary redirect to a different path is not flagged, because sign-in flows and campaigns use them on purpose. The finding (CHECK) is "A permanent move uses 302" or "2 permanent moves use 302 and 307", and recommends 301 or 308; 308 keeps the request method, which matters for POST endpoints ([Section 15.4.9](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.9)). ### Chain length and cost - **No redirects** (PASS): the address answers directly. - **One redirect** (PASS): a single hop to the final address. - **n redirects before the page** (CHECK): two or more redirects in a completed chain, with the milliseconds the extra hops cost, which is the summed time of every hop but the last. - **Crosses n hosts** (INFO): more than two host names in the chain, each needing its own DNS lookup and connection. - **A relative Location** (INFO): a Location without a scheme, allowed by [RFC 9110 Section 10.2.2](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.2) and resolved per [RFC 3986 Section 5](https://www.rfc-editor.org/rfc/rfc3986#section-5); some old clients mishandle it. - **304 Not Modified** (INFO) as the final status: a cached response, not a redirect. ### Where the chain ends A completed chain whose final status is 500 or more is "Ends in a server error (503)" (FAIL); 400 to 499 is "Ends at 404 Not Found" (FAIL): the chain leads to a missing or refused page. Both take the headline, before any plain-HTTP verdict. ### Pasted output rules Pasted responses are analysed with the same function, with two differences. A last response that is still a redirect gives "The pasted output ends on a redirect" (INFO) and the incomplete verdict, and the rules that need a completed chain (redirect count, final status, plain HTTP) are not applied. No timings exist, so the cost finding carries 0 ms. ### Heal it For a live chain that completed with a redirect and a final status under 400, Heal it offers **Check the final address**: it replaces the input with the final URL and traces it again, so you can see it answer without redirects. It changes nothing on your site. Looping, interrupted and failing traces offer no repair. ## Standards and conformance The checker is an observer. Our server behaves as a client that never follows redirects on its own, so every hop is seen as sent; the page then judges the chain with the rules above. It does not claim conformance as a user agent: it never sends cookies, never changes method, and never retries. ### RFC 9110: HTTP Semantics [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110) is an Internet Standard (STD 97, June 2022) and replaces the earlier HTTP semantics documents, including [RFC 2818](https://www.rfc-editor.org/rfc/rfc2818) and parts of [RFC 7230](https://www.rfc-editor.org/rfc/rfc7230), and updates [RFC 3864](https://www.rfc-editor.org/rfc/rfc3864). | Section | Requirement | What the tool does | | --- | --- | --- | | [15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4) | 3xx status codes indicate further action; 301, 302, 303, 307 and 308 carry a Location the client may follow | Only these five are followed; 300 and 304 end the chain | | [10.2.2](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.2) | Location is a URI reference, resolved against the target URI | Resolved against the requested address; a relative value is noted | | [15.4.2](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.2), [15.4.3](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.3) | 301 is permanent and cacheable by default; 302 is temporary | Canonical moves on 302, 303 or 307 are CHECK | | [15.4.8](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.8), [15.4.9](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.9) | 307 and 308 keep the request method | The fix text prefers 308 for endpoints that take POST | | [15.5](https://www.rfc-editor.org/rfc/rfc9110#section-15.5), [15.6](https://www.rfc-editor.org/rfc/rfc9110#section-15.6) | 4xx client errors, 5xx server errors | A final 4xx or 5xx is FAIL | The downgrade rule and the chain-length rule are the tool's own, not RFC requirements: RFC 9110 allows a redirect to any URI and any number of hops. The RFC's note that clients "SHOULD detect and intervene in cyclical redirections" ([Section 15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4)) is implemented as the loop stop. ### RFC 9111: HTTP Caching [RFC 9111](https://www.rfc-editor.org/rfc/rfc9111) is an Internet Standard (STD 98) and obsoletes [RFC 7234](https://www.rfc-editor.org/rfc/rfc7234). The chain shows Cache-Control on redirect hops because [Section 3](https://www.rfc-editor.org/rfc/rfc9111#section-3) lets a cache store a 301 or 308 response, and a browser that cached the old rule keeps sending visitors to the old address after the rule changes. The tool reports the header; it does not simulate a cache. ### RFC 3986: URI resolution [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) is an Internet Standard (STD 66). [Section 5](https://www.rfc-editor.org/rfc/rfc3986#section-5) is used to resolve a relative Location against the address just requested, in the browser for pasted output and on the server for a live trace. ### Where the tool stops - Redirects performed by a page itself (a `meta http-equiv="refresh"` element, a script, a `Refresh` header) are not followed. - Cookies set on one hop are never sent on the next, so a site that redirects by cookie or by language can behave differently in a browser. - Only GET is sent; a chain that behaves differently for POST or HEAD is not seen. - The trace comes from one location at one moment; a geo-aware or load-balanced site can answer differently elsewhere. ## Finding reference Each row is a finding the code can emit, with the stop or rule behind it. ### Failures | Finding | Rule | What it means | Fix | | --- | --- | --- | --- | | Redirect loop | Stop `loop` | Browsers stop with "too many redirects"; nobody reaches the page | Make the proxy and the origin agree on scheme and host; stop apex and www rules pointing at each other; stop one rule adding a slash while another removes it | | Stopped after 15 hops | Stop `limit` | Browsers give up after about 20 redirects, crawlers much sooner | Point the first address straight at the last | | Redirects to an address we will not follow | Stop `unsafe` | The Location is private, reserved, on an unusual port, carries credentials or uses another scheme; often an internal host leaked from a Host header | Set the public host name in the application or proxy | | … did not answer | Stop `error` | DNS, connection, TLS or HTTP failure, a timeout, or a redirect without Location | Fix the stage named in the message | | Drops from HTTPS to plain HTTP | `to plain HTTP` label | Everything after that hop can be read or changed on the network | Write rule targets with `https://` | | Ends in a server error (5xx) | Final status 500 or more | The destination fails | Fix the destination, then the chain | | Ends at 4xx | Final status 400 to 499 | The chain leads to a missing or refused page | Point the first redirect at a page that exists | ### Checks | Finding | Rule | What it means | Fix | | --- | --- | --- | --- | | A permanent move uses 302 (303, 307) | Canonical change with a temporary code | Search engines keep the old address and browsers do not cache the redirect | Use 301, or 308 where the method must survive | | n redirects before the page | Two or more redirects, chain completed | Each one costs a round trip, shown in milliseconds | Redirect in one step; update links, canonical tags and sitemaps to the final address | | Final address uses plain HTTP | Completed chain lands on `http:` | Traffic to the page is unencrypted | Configure HTTPS at the destination | ### Passes and information | Finding | Rule | What it means | | --- | --- | --- | | No redirects | Zero redirects | The address answers directly | | One redirect | One hop | The usual shape: one canonical hop to the page | | A relative Location | Location without a scheme | Allowed and resolved; some old clients mishandle it | | Crosses n hosts | More than two host names | Each new host costs a DNS lookup and a connection | | 304 Not Modified | Final status 304 | A cached response, not a redirect | | The pasted output ends on a redirect | Pasted, last response is a redirect | curl stopped early; run it with `-L` | ## Guide ### A redirect loop 1. Read the last two rows of the chain: the closing hop repeats an earlier address, and its labels say what flips back and forth (`to HTTPS` then `to plain HTTP`, `adds www` then `drops www`, a slash added then removed). 2. Find the two layers that disagree. The commonest pair is a CDN or proxy that redirects to HTTPS while the origin, which receives plain HTTP from the proxy, redirects back; fix it by trusting the proxy's forwarded-protocol header at the origin or by moving the HTTPS rule to one layer only. 3. Trace the exact starting address again. The verdict should read "Lands on 200 OK". ### A drop to plain HTTP 1. The hop labelled `to plain HTTP` is the rule to change; its Location starts with `http://`. 2. Rewrite the rule's target with `https://`, or make it scheme-relative where the server supports it. 3. Check again; the downgrade finding and the final-address finding should both be gone. ### Two or more redirects 1. Read the labels across the chain: `to HTTPS` on one hop and `adds www` on the next means two rules that could be one. 2. Make the first address redirect straight to the final one, with 301 or 308. 3. Update internal links, the canonical tag and the sitemap to the final address, so visitors and crawlers skip the chain entirely. ### A permanent move with a temporary code 1. The finding names the code. Find the rule or framework call that issued it: many frameworks default to 302. 2. Change it to 301, or 308 when the endpoint receives POST and the method must survive the redirect. 3. Trace again; the chip for the hop should show the new code. ### Ends at an error, or no answer 1. For a 4xx or 5xx, open the final address directly: the page itself is the problem, not the chain. Point the first redirect at an address that answers 200. 2. For "did not answer", the message names the stage: a name that does not resolve (NXDOMAIN) needs a DNS record, a refused connection means nothing listens on that port, a TLS failure usually means a certificate for another name, a timeout points at a firewall. 3. For "Redirects to an address we will not follow", look at the Location on the last hop: an internal host name or address in a public redirect is an application or proxy configuration leak. ### Reproduce the trace outside Tamperbox ```sh curl -sIL -A 'Mozilla/5.0' http://example.com/old-page | grep -iE '^(HTTP/|location:)' ``` `-I` sends HEAD, so a site that treats HEAD and GET differently can show a different chain; use `-sL -o /dev/null -D -` for GET. Paste the full output into the page to have it read in your browser. ### Break it cases | Case | What loads | What it shows | | --- | --- | --- | | Start at http:// | Your address with `http://` in place of `https://`, or the sample | The HTTPS hop as the first redirect | | Redirect loop | `http://loop.harbor-supply.example/` | Two hops that send each other back, the FAIL and the closing row | | Long chain | `http://old.harbor-supply.example/catalogue` | HTTPS, then a 302 to the www host: a permanent move on a temporary code, and two redirects before the page | | HTTPS to HTTP | `https://shop.harbor-supply.example/` | A 302 down to plain HTTP with an old Apache behind it | | Ends at a 404 | `https://www.harbor-supply.example/mooring-line` | A chain that lands on a missing page | | Too many hops | `http://chain.harbor-supply.example/1` | A chain that never stops, cut at 15 | | No such host | `http://nohost.` plus your domain, or the sample's | A DNS failure on the first hop | Cases marked "built from your input" start from the address in the box; the reserved `harbor-supply.example` names are answered in the browser and never requested. Heal it after a break offers to restore the input you had. ## Worked example The page opens on `tamperbox.dev`, traced live from `http://tamperbox.dev/` by our server when the page loads. Read the result top down: the verdict names the final status and address and the number of redirects; the chip repeats the count; the chain shows the `to HTTPS` hop first, with its status code, Location, Server and Cache-Control, then the final page with its headers behind the disclosure; the bars compare each hop's time to the first byte from our server. The exact codes, hosts and timings are live evidence and change with the site's configuration and with the moment of the check, so they are not reproduced here. Replace the address in the box to trace your own, or press a Break it case to see each failure on the reserved sample. ## For agents The Tamperbox MCP server exposes two MCP tools: use `search` to inspect the catalog and schema, then use `execute` to call `POST /v1/tools/redirect_checker` through `tamperbox.request`. Its required `url` is a full public `http://` or `https://` address; private, loopback and reserved targets are rejected. The result carries `input`, `hops` (one entry per request with `url`, `status`, `statusText`, `location`, `headers`, `timeMs` and `error`) and `stopped` (`final`, `loop`, `limit`, `error` or `unsafe`), plus warnings and provenance. Apply the rules in [Method](#method) to read it, and keep these warnings with any conclusion: - The chain was requested from one location at one moment, with GET and without cookies. A browser, another region or another method can see a different chain. - Redirects done by a page's own markup or script are not seen. - A final 200 proves the address answered, not that it is the page the owner intended. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the URL travels. ## Limits - At most 15 hops; the chain is cut there and reported as still redirecting. - Only HTTP redirects are followed. A meta refresh, a script redirect or a `Refresh` header is not. - No cookies are stored or replayed between hops, so cookie-dependent redirects can differ in a browser. - Only GET is sent, with a fixed user agent and `Accept-Encoding: identity`. - Times are measured from our server to the end of each hop's headers; they are not what a visitor elsewhere sees. - Cookie and authentication headers are left out of the evidence. - Pasted output carries no timings and cannot be checked for private targets. - History is a browser interaction record, not server monitoring. Explicit tool links use temporary browser storage as described in [Browser transfers](#browser-transfers). ## References - [RFC 9110, HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110). Internet Standard, STD 97, June 2022; replaces the earlier HTTP semantics documents, including [RFC 2818](https://www.rfc-editor.org/rfc/rfc2818) and parts of [RFC 7230](https://www.rfc-editor.org/rfc/rfc7230), and updates [RFC 3864](https://www.rfc-editor.org/rfc/rfc3864). Sections used: [10.2.2](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.2), [15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4), [15.4.2](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.2), [15.4.3](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.3), [15.4.8](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.8), [15.4.9](https://www.rfc-editor.org/rfc/rfc9110#section-15.4.9), [15.5](https://www.rfc-editor.org/rfc/rfc9110#section-15.5) and [15.6](https://www.rfc-editor.org/rfc/rfc9110#section-15.6). - [RFC 9111, HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111). Internet Standard, STD 98, June 2022; obsoletes [RFC 7234](https://www.rfc-editor.org/rfc/rfc7234). Section used: [3](https://www.rfc-editor.org/rfc/rfc9111#section-3). - [RFC 3986, Uniform Resource Identifier (URI): Generic Syntax](https://www.rfc-editor.org/rfc/rfc3986). Internet Standard, STD 66; updated by [RFC 7320](https://www.rfc-editor.org/rfc/rfc7320) and [RFC 8820](https://www.rfc-editor.org/rfc/rfc8820). Section used: [5](https://www.rfc-editor.org/rfc/rfc3986#section-5). - [RFC 9112, HTTP/1.1](https://www.rfc-editor.org/rfc/rfc9112). Internet Standard, STD 99; the status line and header field syntax that pasted curl output follows. Section used: [4](https://www.rfc-editor.org/rfc/rfc9112#section-4). --- # Reverse DNS Lookup How the Reverse DNS Lookup finds the PTR name of each address, checks that the name resolves back to the same address the way mail receivers do, and what each finding means for a server that sends mail. Canonical: https://docs.tamperbox.dev/tools/reverse-dns/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: Up to 20 IPv4 or IPv6 addresses, or a domain Outputs: A verdict across the addresses, one row per address with its reverse name, whether it points back and the network that holds it, findings worst first, and the underlying PTR and forward-lookup evidence Limitations: One public resolver at one moment; at most 20 addresses; the generic-name test is a heuristic, and the name a server announces in its SMTP greeting is not seen The tool page is [tamperbox.dev/reverse-dns](https://tamperbox.dev/reverse-dns). It opens with a live lookup of `tamperbox.dev` and takes a list of addresses or a domain. This page is the long version: how a reverse name is found, what "points back" means and why mail receivers care, every finding, and how to fix each one with whoever holds the address. <div class="tb-callout"><strong>Where processing happens:</strong> each public address is sent to the Tamperbox server, which asks public DNS for its PTR record and for the addresses of each name returned, and looks up the network that holds it. Private, loopback, link-local and documentation addresses are explained in your browser and never looked up. History stays in memory in the open page. Explicit links to another tool may temporarily keep a one-use transfer in browser session storage; transfers expire after one minute and do not put the input in the URL.</div> ## What the tool answers A PTR record maps an address back to a name. Mail receivers use it to ask a connecting server "who are you?", and then check that the name it gives leads back to the same address. The tool answers, for each address: 1. **Does it have a reverse name?** The PTR record at its reverse name under `in-addr.arpa` or `ip6.arpa`. 2. **Does the name point back?** Whether the name's A or AAAA records include the address: forward-confirmed reverse DNS. 3. **Does the name look like a provider's default?** A heuristic for names built from the address. 4. **Who holds the address?** The network associated with it. That label is a starting point for finding the provider, not proof of who controls the reverse zone. It does not check the name a server announces in its SMTP greeting (HELO or EHLO), does not test whether the address is on a blocklist, and does not send mail. ## Inputs ### IP addresses One or more addresses separated by spaces, commas or new lines; duplicates are dropped and the first 20 are checked (with more, the verdict says "The first 20 of N are shown"). A list made only of addresses is checked as soon as it is complete, without waiting for typing to pause. Each IPv4 part must be a number from 0 to 255 written without leading zeros; otherwise the check stops with "203.0.113.256 is not an IPv4 address: each part must be 0 to 255." Use ordinary compressed or expanded hexadecimal IPv6. The browser uses a permissive colon-and-hex detector, not a complete IPv6 parser; dotted IPv4 suffixes and scope identifiers are not accepted by that detector. ### A domain `example.com`. When you stop typing (or on Enter), the domain's A and AAAA records are looked up and each address is checked. A domain with neither stops with "example.com has no address to look up." Before a domain is checked, pasted text is reduced to what the tool takes: `https://www.example.com/contact` becomes `www.example.com`, an email address becomes its domain, quotes and brackets are dropped. Text that contains nothing usable stays as pasted and the page explains why. Typing is never rewritten mid-word, and Break it loads are never cleaned. ### Files Drop a text file on the page, or open one with Add a file: it is read in the browser, up to 256 KiB, and never uploaded. A list of addresses exported from a log works. ## Reading the result ### Verdict and chips For one address the verdict is its outcome: the name and "points back to this address", "does not point back", "No PTR record", or "Private address". For several it counts them: "3 of 3 addresses have a name; 2 point back." The chips count confirmed names, names not confirmed, and addresses without a PTR; each scrolls to the table. ### Findings Findings report addresses without PTR and names not forward-confirmed (CHECK), plus generic names (INFO). Successful forward confirmation also produces a PASS finding, and private or special addresses produce an INFO finding. Multiple passing checks are folded. The [finding reference](#finding-reference) lists every finding. ### Reverse names One row per address: the address with the reverse name it was looked up at, the PTR name or names (or "No PTR record", or why a private address has none), whether each name points back, and the network that holds the address with its AS number. On phones each row becomes a card. ### History and next checks History appears below the result evidence after Break it or Heal it changes the input. Revert restores the input before the latest recorded change; Reset input returns to the input before the first recorded change. Typing or pasting a new input starts a new history. Restoring a live input runs the lookup again, rather than restoring a saved response. Take it further uses values derived from the results: the domain of a non-generic PTR name for SPF, an AS number for the announcing network, or a non-sample PTR hostname on port 25 for a certificate check. These links are conditional on the evidence returned. ## Method ### 1. Reading the input A text in which every word is an IP address is a list; anything else is read as a domain. For a domain the A and AAAA records are fetched and their addresses become the list. Duplicates are dropped, IPv4 parts are validated, and the first 20 are kept. ### 2. Addresses with no public reverse name These are recognised before any query and explained without a lookup: 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 ([RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3)); 127.0.0.0/8 and `::1` (loopback); 169.254.0.0/16 and addresses starting `fe80:` (link-local); 100.64.0.0/10 (shared address space, [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598#section-7)); `fc00::/7` (unique local IPv6); and the unspecified addresses. Their result rows explain why the address is not queried. Documentation addresses (192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 and `2001:db8::/32`) are answered from the sample zone in the browser. ### 3. The reverse name and its PTR Each address is turned into the name its PTR record lives at. IPv4 octets are reversed under `in-addr.arpa` ([RFC 1035, section 3.5](https://www.rfc-editor.org/rfc/rfc1035#section-3.5)), so 203.0.113.80 becomes `80.113.0.203.in-addr.arpa`. IPv6 is expanded to 32 hex digits, reversed one digit at a time and placed under `ip6.arpa` ([RFC 3596, section 2.5](https://www.rfc-editor.org/rfc/rfc3596#section-2.5)). A PTR query is made at that name; every PTR answer is a name. An address with no PTR answer gives "N addresses without a PTR record" (CHECK). [RFC 1912, section 2.1](https://www.rfc-editor.org/rfc/rfc1912#section-2.1): "Every Internet-reachable host should have a name", and "For every IP address, there should be a matching PTR record in the in-addr.arpa domain." ### 4. Forward confirmation For every name returned, the A records (for an IPv4 address) or AAAA records (for IPv6) of that name are fetched, and the original address is looked for among them; IPv6 addresses are compared in normalized form, so compressed and expanded spellings match. This is the "iprev" test of [RFC 8601, section 3](https://www.rfc-editor.org/rfc/rfc8601#section-3): "If the client peer's IP address is I, the list of names to which I maps (after a "PTR" query) is the set N, and the union of IP addresses to which each member of N maps … is L, then this test is successful if I is an element of L." A row passes ("Points back") when any of its names resolves to the address. Otherwise it shows "Points elsewhere" and counts toward "N names not forward-confirmed" (CHECK), with each name and the address it does not resolve to. A forward lookup that fails also counts as not confirmed. ### 5. Generic names A name is called generic when it contains both of the last two parts of the address (for 203.0.113.80, both `113` and `80`), or contains one of the words dyn, dynamic, pool, dsl, cable, dhcp, static, ip, host, cust, client, ec2 or compute at the start or after a dot or hyphen. It gives "N generic names" (INFO): fine for a web server, weaker for a mail server. Short octets make the number test loose; treat it as a prompt to look, not a verdict. ### 6. The network Each public address is also looked up for the network that announces it; the row shows the network's name and AS number. A failure here leaves the cell empty and does not affect the result. ### 7. The verdict | Situation | Verdict | Level | | --- | --- | --- | | One private or special address | "Private address: … has no public reverse name." | INFO | | One address, no PTR | "No PTR record for …" | CHECK | | One address, name points back | "name points back to this address." | PASS | | One address, name does not point back | "name does not point back to …" | CHECK | | Several addresses | "N of M addresses have a name; K point back." | CHECK if any lacks a PTR or is not confirmed, else PASS | ## Standards and conformance | Specification | Sections used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035) | [3.5](https://www.rfc-editor.org/rfc/rfc1035#section-3.5), IN-ADDR.ARPA | IPv4 reverse names | | | [RFC 3596](https://www.rfc-editor.org/rfc/rfc3596) | [2.5](https://www.rfc-editor.org/rfc/rfc3596#section-2.5), IP6.ARPA | IPv6 reverse names, nibble by nibble | | | [RFC 8601](https://www.rfc-editor.org/rfc/rfc8601) (obsoletes RFC 7601) | [3](https://www.rfc-editor.org/rfc/rfc8601#section-3), the iprev method | Forward confirmation exactly as the algorithm states | RFC 8601 asks verifiers to limit the names evaluated; the tool evaluates every name a PTR returns, without an explicit per-address PTR-name cap in the browser; the MCP operation caps it at 20 | | [RFC 1912](https://www.rfc-editor.org/rfc/rfc1912) (informational) | [2.1](https://www.rfc-editor.org/rfc/rfc1912#section-2.1) | The basis of the missing-PTR and mismatch findings | Its rule that a PTR must not point at a CNAME is not checked separately | | [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918), [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598), [RFC 4291](https://www.rfc-editor.org/rfc/rfc4291#section-2.5.6), [RFC 4193](https://www.rfc-editor.org/rfc/rfc4193#section-3.1) | Private, shared, link-local and unique local ranges | Recognised in the browser without a lookup | | | [RFC 5737](https://www.rfc-editor.org/rfc/rfc5737), [RFC 3849](https://www.rfc-editor.org/rfc/rfc3849) | Documentation ranges | Answered from the sample zone | | RFC 8601 itself notes that "there is some contention regarding the wisdom and reliability of this test", and leaves the details to each verifier. Receivers do apply it: Gmail's [email sender guidelines](https://support.google.com/a/answer/81126) tell senders to ensure that sending IPs have valid forward and reverse DNS records. The tool reports the test as RFC 8601 states it; what a given receiver does with a failure is its own policy. ## Finding reference | Finding | Severity | Source | What it means for a sending server | Fix | | --- | --- | --- | --- | --- | | N names point back (finding); Points back (row) | PASS | [RFC 8601 3](https://www.rfc-editor.org/rfc/rfc8601#section-3) | Passes iprev | Keep PTR and A in step on moves | | N addresses without a PTR record | CHECK | [RFC 1912 2.1](https://www.rfc-editor.org/rfc/rfc1912#section-2.1) | Many receivers refuse or score down the mail | [Set a PTR](#setting-a-ptr-record) at whoever holds the address | | N names not forward-confirmed | CHECK | [RFC 8601 3](https://www.rfc-editor.org/rfc/rfc8601#section-3) | Fails iprev: the name is treated as unverified | [Fix the A record or the PTR](#a-name-that-points-elsewhere) | | N generic names | INFO | | Valid, but trusted less for mail | Use a name under your own domain | | N private or special addresses | INFO | [RFC 1918 3](https://www.rfc-editor.org/rfc/rfc1918#section-3) | Not on the internet; no public name | Check the public address instead | | Not an IPv4 address (stops the check) | | | | Correct the address | | No address to look up (stops the check) | | | The domain has no A or AAAA | Check the domain or enter addresses | ## Guide ### Setting a PTR record 1. Find who holds the address: the network column, or [WHOIS on the address](https://tamperbox.dev/whois-lookup). For a server at a hosting or cloud provider, it is the provider. 2. In the provider's panel, find the reverse DNS (rDNS, PTR) setting for the address; some providers set it only through a support request. If you hold the block yourself, ask your upstream to delegate the reverse zone to your nameservers. 3. Set the PTR to a name under your own domain, such as `mail.example.com`. 4. Make sure that name has an A record (or AAAA for IPv6) with exactly this address. 5. Check here: the row should read "Points back". ### A name that points elsewhere Decide which side is wrong. If the PTR name is meant for this server, add or correct its A or AAAA record. If the PTR names something else (the bare domain, which points at the web host, is the commonest case), change the PTR to a name that already resolves here. After a migration, both the PTR of the new address and the A record of the old name usually need updating. ### IPv6 sending If the server sends over IPv6, its IPv6 address needs a PTR too, and the name needs an AAAA record. Some providers set reverse DNS only for IPv4 by default. ### Independent check ```sh # The PTR name of an address dig +short -x 198.51.100.24 # The addresses of that name: the original address must be among them dig +short A out.example.com dig +short AAAA out.example.com ``` ### Break it cases The first three cases append an address to the current list, or to the addresses resolved from the current domain. If no usable list is available, they use a small sample list. A domain replaces the input with a reserved sample domain. | Case | What it adds or loads | What it shows | | --- | --- | --- | | Address without PTR | `192.0.2.150`, a documentation address with no PTR | "1 address without a PTR record" | | Name points elsewhere | `198.51.100.81`, whose name resolves to another address | "1 name not forward-confirmed" | | Private address | `10.20.4.17` | The private range, explained without a lookup | | A domain | `harbor-supply.example` | Domain mode: the domain's own addresses | ## Worked example The page opens by resolving `tamperbox.dev` live, then looking up the PTR and forward records for its returned addresses. The set of addresses and their reverse names can change. Read the number of named addresses and the number that point back separately: a PTR alone does not establish forward confirmation. For each row, compare the original address with the addresses returned for its PTR name. A missing PTR on a web-hosting address is not proof that the website is broken. The same observation on an actual outgoing mail address is relevant to receiver policy, but the tool does not establish whether this address sends mail. For a repeatable offline contrast, enter `198.51.100.24` and `203.0.113.80`, one per line. These documentation addresses show a confirmed name and a generic cloud-style name. Then choose Address without PTR or Name points elsewhere to append that case. Treat the names and network labels as sample data. Heal it restores the previous input; restoring the live domain starts new queries and can produce different results. ## For agents Search the Tamperbox MCP catalog for `reverse_dns` and inspect its schema. It accepts one public `ip`, not the browser's domain or address list. Resolve a domain separately if needed. The result includes PTR evidence, names and forward-confirmation evidence for at most 20 distinct PTR names, with `totalNames` and `truncated`. An unavailable forward lookup has `forwardConfirmed: null`, rather than false. It does not return the browser's generic-name or network-provider assessment. Keep these warnings with any conclusion: - One public resolver at one moment; caches elsewhere may differ, especially right after a PTR change. - Forward confirmation is the RFC 8601 iprev test; what a receiver does with a failure is its own policy. - The generic-name finding is a heuristic. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) for the calling pattern and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the addresses travel. ### Keeping an observation reproducible Record the target, the time of the lookup, the relevant raw records and the resolver or registry that supplied them. Repeat a live lookup after a configuration change instead of assuming a restored input restores an old response. A saved RDAP object or pasted DNSSEC record set is a snapshot: its dates are assessed against the current clock, but its contents are not refreshed. Separate absence from failure. A successful response with no applicable record, a rejected input, a timeout and an upstream error support different conclusions. Preserve an error when a query could not complete; do not replace it with a claim that the record does not exist. When sharing findings, include the narrow observation and the relevant limitation rather than only the verdict label. ## Limits - One public resolver, from one place, at one moment. - At most 20 addresses per check. - The name in a server's SMTP greeting, blocklists and delivery itself are not checked. - "Generic name" is a heuristic. - Break it fixtures use documentation addresses answered in the browser. - History stays in memory in the open page. Explicit links to another tool may temporarily keep a one-use transfer in browser session storage; transfers expire after one minute and do not put the input in the URL. ## References - [RFC 1035, Domain Names: Implementation and Specification](https://www.rfc-editor.org/rfc/rfc1035), section 3.5 - [RFC 1912, Common DNS Operational and Configuration Errors](https://www.rfc-editor.org/rfc/rfc1912) (informational), section 2.1 - [RFC 1918, Address Allocation for Private Internets](https://www.rfc-editor.org/rfc/rfc1918), section 3 - [RFC 3596, DNS Extensions to Support IP Version 6](https://www.rfc-editor.org/rfc/rfc3596), section 2.5 - [RFC 3849](https://www.rfc-editor.org/rfc/rfc3849) and [RFC 5737](https://www.rfc-editor.org/rfc/rfc5737), documentation address ranges - [RFC 4193, Unique Local IPv6 Unicast Addresses](https://www.rfc-editor.org/rfc/rfc4193), section 3.1 - [RFC 4291, IP Version 6 Addressing Architecture](https://www.rfc-editor.org/rfc/rfc4291), section 2.5.6 - [RFC 6598, IANA-Reserved IPv4 Prefix for Shared Address Space](https://www.rfc-editor.org/rfc/rfc6598), section 7 - [RFC 8601, Message Header Field for Indicating Message Authentication Status](https://www.rfc-editor.org/rfc/rfc8601), section 3 (obsoletes RFC 7601) - [Gmail email sender guidelines](https://support.google.com/a/answer/81126) --- # Robots.txt & Sitemap Checker How the robots.txt checker fetches and parses a site's rules and sitemaps, which group each crawler obeys, which rule decides a path, every finding it reports, and how to fix each one. Canonical: https://docs.tamperbox.dev/tools/robots-txt-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public host name, or a robots.txt or XML sitemap to paste Outputs: A verdict for search and AI crawlers, findings, a path tester that marks the deciding line, the file line by line, a crawler table for the home page and the sitemaps with their URL counts Limitations: robots.txt is a request crawlers may ignore; the crawler table judges the home page only; at most six sitemaps, 10 MiB each The tool page is [tamperbox.dev/robots-txt-checker](https://tamperbox.dev/robots-txt-checker). It checks `tamperbox.dev` live when opened, says which search engines and AI crawlers the rules let in, and lets you test any path. This page is the long version: how the file is fetched and read, how a crawler's group and a path's rule are chosen, every finding, and how to fix each one. <div class="tb-callout"><strong>Where processing happens:</strong> a pasted robots.txt or sitemap is read in your browser and never uploaded. A host name is sent to the Tamperbox server, which fetches <code>/robots.txt</code> and up to six sitemaps without cookies and returns them; the rules are evaluated in your browser. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. Sample hosts on the reserved <code>.example</code> zone are answered in the browser from a fixture.</div> ## What the tool answers 1. **Can search engines crawl the site?** Googlebot, Bingbot, Applebot and DuckDuckBot at the home page, judged: blocked is a failure. 2. **Which AI crawlers are let in?** Ten AI training, search and on-request tokens, stated without a verdict, because that is the owner's choice. 3. **Is a given URL allowed, and why?** The tester names the deciding line for any path and crawler. 4. **Is the file and its sitemaps well formed?** Every line a crawler would skip or misread, and every sitemap problem. 5. **Do the rules and the sitemap agree?** URLs the sitemap asks to be crawled that the rules refuse. ## Inputs ### A host or address `example.com` or a full address. The host is what is checked; a path in a full address (`https://example.com/shop/boots`) becomes the tester's path. The check runs when you stop typing, or on Enter. The usual refusals apply: spaces, other schemes, credentials, non-standard ports, IP addresses and single labels. ### A pasted robots.txt Text with a newline, a line starting `#`, or a line starting `User-agent:`, `Disallow:`, `Allow:`, `Sitemap:` or `Crawl-delay:` is read as robots.txt, in the browser. Nothing is fetched, so the Sitemaps section stays empty. ### A pasted sitemap Text starting with `<?xml`, `<urlset` or `<sitemapindex` is read as a sitemap, in the browser. Files up to 10 MiB can be dropped or opened (`.txt`, `.xml`). A pasted address loses quotes, brackets and trailing punctuation and keeps the host; text that fits nothing stays as pasted so the error can explain it. ## Reading the result ### Verdict and chips "Open to search engines", "Closed to Googlebot" or "Closed to search engines", then the AI crawlers blocked and the number of things to fix. For a missing file: "No robots.txt. Every crawler may fetch every page." The chips count AI crawlers blocked, sitemap URLs blocked, and problems; each scrolls to its section. Two items say where the input went. ### Findings Every finding, worst first, line findings prefixed with their line; two or more passing findings are grouped under an expandable **checks passed** row. A single passing finding stays visible. ### Test a URL A path or full URL and a crawler. The result says Allowed or Blocked, names the group and the deciding line, and marks that line in the file. It opens on the path from your address, or on the first blocked sitemap URL, with Googlebot. ### robots.txt The file as written, numbered, each line with an issue tinted and noted. Long files show their first 60 lines, every marked line and the tested line; **Show all n lines** lists the rest, and **Show the first 60 lines** folds it again. Folding is offered only when at least ten unmarked lines after line 60 can be hidden; marked lines remain visible. ### Crawlers at the home page Two tables, search engines and AI crawlers: who runs each token, Allowed or Blocked at `/`, and the deciding rule or group. ### Sitemaps Each sitemap fetched, its status, URL count, last change, and up to three issues. ### History History follows the current result evidence. Break it and Heal it record input changes, newest first. **Revert** restores the input before the latest recorded change; **Reset input** restores the input before the first retained change and clears the list. **Restore input before this break** under Heal it also reverts the latest change. These actions reload and check the restored input. Restoring a public address can therefore send a new request, including on the two tools whose ordinary typing waits for a run button. Editing or pasting a new input clears History. The list lives in the current page; it is not saved monitoring data and does not restore an old network response. ### Take it further Only links with an available result value appear. | Follow-up | Value carried | When offered | | --- | --- | --- | | [Redirect Checker](https://tamperbox.dev/redirect-checker) | `https://host/robots.txt` | A host was checked | | [Website Down Checker](https://tamperbox.dev/website-down-checker) | First included sitemap URL | A host check includes a sitemap result | | [Open Graph Preview](https://tamperbox.dev/open-graph-preview) | First page URL found in sitemap entries | A page URL is available, including in a pasted sitemap | | [security.txt Checker](https://tamperbox.dev/security-txt-checker) | Checked host | A host was checked | ### Related checks and input transfer Check the rest carries the current address to a sibling tool. Take it further carries the specific value listed above. Pasted file contents are not transferred through these links. Transfers temporarily use browser `sessionStorage` with a one-use random token in the URL fragment; the input itself is not in the URL. The destination accepts a transfer for less than one minute and removes the token. Manual destination tools wait for their run button or Enter. Each destination collects new evidence. A follow-up link does not confirm the original verdict or repair the remote site. ### Result cards Six expandable cards below the result explain its meaning, give a beginner explanation, offer an agent prompt, describe good practice, suggest fixes and state limitations. Their text follows the current result; it is not another measurement. Open a card for its full explanation and the relevant [Method](#method) or [Guide](#guide). The agent prompt can be copied for review; copying it does not run a repair or send it to an agent. ## Method ### Fetching The server requests `https://<host>/robots.txt` with `TamperboxBot/1.0`, follows up to 5 redirects and reads the first 512 KiB. [RFC 9309, section 2.3.1.2](https://www.rfc-editor.org/rfc/rfc9309#section-2.3.1.2): crawlers "SHOULD follow at least five consecutive redirects". Up to three Sitemap URLs are then fetched (or `/sitemap.xml` when none is listed), with sitemap index children until six sitemaps have been read; each is decompressed if gzipped and read up to 10 MiB. ### The response before any rule | Response | Severity | Why | | --- | --- | --- | | 500 or above | FAIL | [RFC 9309, section 2.3.1.4](https://www.rfc-editor.org/rfc/rfc9309#section-2.3.1.4): on an unreachable status "the crawler MUST assume complete disallow"; Google keeps retrying and after 30 days uses its last copy or crawls everything | | 429 | FAIL | Treated like a server error | | Other 400 to 499 | INFO | [Section 2.3.1.3](https://www.rfc-editor.org/rfc/rfc9309#section-2.3.1.3): "the crawler MAY access any resources on the server" | | HTML content type or body | FAIL | A catch-all route; crawlers find no rules | | Over 500 KiB | CHECK | [Section 2.5](https://www.rfc-editor.org/rfc/rfc9309#section-2.5): "The parsing limit MUST be at least 500 kibibytes"; Google stops there | ### Parsing lines Following [RFC 9309, section 2.2](https://www.rfc-editor.org/rfc/rfc9309#section-2.2): comments after `#` are removed, blank lines skipped, field names read case-insensitively. Consecutive `User-agent` lines form one group, and `Allow` and `Disallow` belong to the group above them. | Line | Severity | Note | | --- | --- | --- | | No `field:` | CHECK | Not a rule; skipped | | `Sitemap:` not an absolute http(s) URL | FAIL | Sitemap is an "other record" ([section 2.2.4](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.4)); the [Sitemaps protocol](https://www.sitemaps.org/protocol.html#submit_robots) asks for the full URL | | `Allow`/`Disallow` before any `User-agent` | CHECK | Ignored; Heal it moves it under `User-agent: *` | | `Dissallow`, `Disalow` and similar | CHECK | Google's parser accepts them; others ignore the line. Heal it fixes the spelling | | Path not starting with `/` or `*` | CHECK | Matches nothing. Heal it adds the slash | | `Noindex` | CHECK | Not a robots.txt rule; Google stopped reading it in 2019. Heal it removes it | | `Crawl-delay`, `Host` | INFO | Google ignores both; Bing and Yandex read Crawl-delay | | Unknown field | CHECK | Skipped | | A group with no rules | INFO | That crawler may fetch everything | | A byte order mark | INFO | Some small crawlers misread the first line | ### Which group a crawler obeys [RFC 9309, section 2.2.1](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.1): "If there is more than one group matching the user-agent, the matching groups' rules MUST be combined", and a crawler without a matching group obeys the `*` group. The tool matches the product token case-insensitively; if no group names it, the token is shortened at each hyphen (`Google-Extended`, then `google`) before falling back to `*`. A crawler follows only its own group: a `User-agent: Googlebot` group with one Allow line drops every `*` rule for Googlebot. ### Which rule decides a path [RFC 9309, section 2.2.2](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.2): "the most specific match found MUST be used. The most specific match is the match that has the most octets. ... If an allow rule and a disallow rule are equivalent, then the allow rule SHOULD be used." The tester approximates those rules: - the path includes the query; percent-escapes of unreserved characters are decoded, others upper-cased, on both sides ([section 2.2.2](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.2)); - `*` matches any run of characters and a final `$` anchors the end ([section 2.2.3](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.3)); every other rule is a prefix; - the longest raw pattern wins by JavaScript string length, excluding a final `$`; Allow wins a tie. This is not an octet-length comparison for every Unicode or percent-encoded spelling; - an empty `Disallow` matches nothing, and `/robots.txt` is always allowed ([section 2.2.2](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.2)). With `Disallow: /shop/` and `Allow: /shop/sale`, `/shop/sale/boots` is allowed: the Allow rule is longer. ### The crawler table 14 tokens at `/`: Googlebot, Bingbot, Applebot and DuckDuckBot (search, judged), GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-SearchBot, PerplexityBot, Google-Extended, Applebot-Extended, CCBot and Bytespider (AI, stated). Google-Extended and Applebot-Extended are control tokens read by their owners' crawlers, not crawlers themselves. When all four search crawlers are blocked, "Every search engine is blocked" leads the findings. That title describes only these four catalogued search tokens at `/`, not every crawler or every path. ### Sitemaps Read as the [Sitemaps protocol 0.9](https://www.sitemaps.org/protocol.html) defines: | Sitemap issue | Severity | | --- | --- | | An HTML page; no `<urlset>` or `<sitemapindex>`; no closing tag | FAIL | | An entry without `<loc>`; an unescaped `&` in `<loc>`; a relative `<loc>` | FAIL | | More than 50,000 entries | FAIL | | No sitemaps.org namespace | CHECK | | A URL on another host | CHECK | | A `lastmod` that is not a [W3C date](https://www.w3.org/TR/NOTE-datetime) or is more than a day ahead | CHECK | | No entries | CHECK | | A listed sitemap answering 400 or more, or not at all | CHECK | | Listed twice; `changefreq` or `priority` present | INFO | Then the cross-check: sitemap URLs that Googlebot may not fetch are CHECK. No Sitemap line is INFO, with a repair that adds one when `/sitemap.xml` answered. ## Standards and conformance ### RFC 9309, Robots Exclusion Protocol Implemented: groups and combination (2.2.1), longest match with Allow on ties (2.2.2), `*` and `$` (2.2.3), access results by status (2.3.1), the 500 KiB parsing limit (2.5), five redirects. Lenient where Google is: the misspellings of Disallow are reported but evaluated as Disallow, as Google's open-source parser does. Not part of RFC 9309 but reported: `Sitemap` (widely supported, and mentioned as an "other record" in [section 2.2.4](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.4)), `Crawl-delay`, `Host`, `Noindex`. RFC 9309 has no predecessor RFC; it standardised the 1994 convention. ### Sitemaps protocol 0.9 Implemented: both root elements, `loc`, `lastmod`, the 50,000 entry and 50 MiB limits, escaping, same-host URLs. Live fetching and file drops stop at 10 MiB. The parser also has a 50 MiB size rule, but those bounded inputs cannot exercise it; it is not evidence that a larger original file was fully validated. Text sitemaps and image or news extensions are not read. ### Crawler documentation Tokens and their meaning come from each operator's own crawler documentation; their behaviour beyond RFC 9309 is not verified. ## Finding reference ### File and record findings | Finding | Severity | What it means for crawlers | Fix | | --- | --- | --- | --- | | Every search engine is blocked | FAIL | All four catalogued search tokens are denied at `/` | Remove `Disallow: /` from `*` | | robots.txt answered 5xx or 429 | FAIL | Google crawls nothing | Serve the file statically | | robots.txt is an HTML page | FAIL | No rules found | Serve a text file before the catch-all | | robots.txt is n KiB | CHECK | Rules past 500 KiB ignored | Use wildcards | | No robots.txt (n) | INFO | Everything allowed | Optional | | Line n: Sitemap must be a full URL | FAIL | Sitemap not found | Full https:// address | | Line n: Rule before any User-agent | CHECK | Ignored | Move under a group | | Line n: "x" is a misspelling of Disallow | CHECK | Only Google obeys | Spell Disallow | | Line n: Path does not start with / | CHECK | Matches nothing | Add the slash | | Line n: Noindex in robots.txt does nothing | CHECK | Pages can still be indexed | Use meta robots or X-Robots-Tag | | Line n: Not a rule, Unknown field | CHECK | Skipped | Rewrite or remove | | Line n: Crawl-delay is not read by Google, Host is obsolete | INFO | Partly ignored | Optional | | Line n: No rules for x | INFO | That crawler may fetch everything | Add rules or remove the group | | Line 1: Starts with a byte order mark | INFO | First line misread by some | Save without BOM | ### Sitemap findings | Finding | Severity | What it means for crawlers | Fix | | --- | --- | --- | --- | | n sitemap URLs are blocked by robots.txt | CHECK | Conflicting signals | Narrow the rule or drop the URL | | No Sitemap line | INFO | Sitemap found more slowly | Add one (Heal it) | | Sitemap answered n, did not answer | CHECK | Skipped by crawlers | Fix the address | | sitemap: (each issue in the table above) | as listed | | | ## Guide ### The site is closed to search engines 1. Open the file and find `Disallow: /` in the `*` group (or a search crawler's group). 2. If the site should be public, remove it or narrow it to the paths that should stay private. 3. Publish at `/robots.txt` and check again. Confirm outside Tamperbox: `curl -s https://example.com/robots.txt`. ### A page you want found is blocked Enter its URL in the tester with Googlebot. The marked line is the one to change; add an `Allow:` for the page or narrow the `Disallow:`. Remember a crawler with its own group ignores `*`. ### robots.txt answers 5xx, 429 or HTML Serve it as a static file outside the application, and exempt the path from bot filters and rate limits. `curl -sI https://example.com/robots.txt` should show `200` and `text/plain`. ### Blocking or allowing AI crawlers Add a group per token you want to block (`User-agent: GPTBot` then `Disallow: /`). Training and search tokens are separate: blocking GPTBot does not block OAI-SearchBot. Google-Extended controls use of content for Google's AI models, not Google Search. ### Sitemap problems Fix the file the generator writes; the sitemap's own issues name the line. Announce it with `Sitemap: https://example.com/sitemap.xml`. ### Break it cases | Case | What it loads | What to look at | | --- | --- | --- | | Block everything | `User-agent: * / Disallow: /` above your file | Closed to search engines | | Misspelled Disallow | Your file with Disallow misspelled | The line marked; Heal it fixes it | | Rule above User-agent | Your first rule moved above every group | Heal it moves it back | | Noindex line | A Noindex line after your first rule | Heal it removes it | | Server error (503) | A sample host whose file answers 503 | Response finding | | Served as a web page | A sample single-page app | robots.txt is an HTML page | | No robots.txt | A sample host without the file | No robots.txt | The first four are built from your own file when you entered a host or pasted one. ## Worked example The page opens with a live check of `tamperbox.dev`. It fetches the current robots.txt and a bounded selection of sitemap files. The crawler table describes permission for `/`; it does not summarize every path on the site. Choose a crawler and enter a path that matters to your site. Read the highlighted deciding rule and compare it with the most specific matching group. An allowed home page can coexist with a blocked checkout or administration path. Likewise, a listed sitemap URL can be blocked by the rules even though the sitemap itself was fetched successfully. Review any suggested repair before copying it into your repository. Heal it replaces the input with corrected text; it does not publish a policy. Recheck a published change by fetching the file independently and testing the affected paths again. Blocking a crawler is a policy choice, not an authentication barrier, and a clean syntax result does not prove that every crawler will obey it. ## For agents Use the Tamperbox MCP `search` tool to inspect the schema, then `execute` with `tamperbox.request` to call `POST /v1/tools/robots_txt_checker`. Supply the required `domain` field as a public domain name. The operation is named `robots_txt_checker`; the browser page’s hyphenated identifier is not the API operation name. The response contains file `evidence`, HTTP `response` interpretation and a parsed `report`. It does not fetch the sitemap collection or reproduce the browser’s path-testing table. Sitemap declarations are parsed URLs, not proof that the files or their pages were retrieved. Keep the input, observation time, source limitations and inconclusive results with any summary. Browser fixtures are demonstrations, not live MCP targets. Do not turn missing evidence into a passing check or infer that an inaccessible resource has been deleted. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/), [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) and [Security and privacy](https://docs.tamperbox.dev/reference/security/). ## Limits - One fetch of robots.txt (512 KiB, 5 redirects) and up to six sitemaps (10 MiB each). - The crawler table is for `/` only. - Crawler-specific extensions beyond RFC 9309 are not evaluated. - Live checks are rate limited. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. ## References - [RFC 9309, Robots Exclusion Protocol](https://www.rfc-editor.org/rfc/rfc9309): sections [2.2](https://www.rfc-editor.org/rfc/rfc9309#section-2.2), [2.2.1](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.1), [2.2.2](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.2), [2.2.3](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.3), [2.2.4](https://www.rfc-editor.org/rfc/rfc9309#section-2.2.4), [2.3.1](https://www.rfc-editor.org/rfc/rfc9309#section-2.3.1), [2.5](https://www.rfc-editor.org/rfc/rfc9309#section-2.5). Proposed standard, 2022. - [Sitemaps XML format, protocol 0.9](https://www.sitemaps.org/protocol.html). - [W3C Date and Time Formats](https://www.w3.org/TR/NOTE-datetime). --- # SaaS Stack Detector How Tamperbox reads public TXT records for service-verification tokens and SPF senders without claiming that an account is active. Canonical: https://docs.tamperbox.dev/tools/saas-stack/ Updated: 2026-10-25 Applies to: tamperbox.dev, October 2026 Prerequisites: a domain name or pasted DNS TXT records Outputs: recognised services, possible duplicate tokens, SPF sender domains, unknown verification-shaped records and the original TXT evidence Limitations: Public observations are time-sensitive and do not prove ownership, intent or private configuration The tool page is [tamperbox.dev/saas-stack](https://tamperbox.dev/saas-stack). It opens with a live lookup of `mozilla.org`; replace it to inspect your own target. This guide documents the actual input path, evidence contract, classifications and independent verification steps. <div class="tb-callout"><strong>Where processing happens:</strong> input cleanup, pasted-data parsing and report rendering happen in the browser. Live checks send only the validated public target to the Tamperbox server and the public services required for the lookup. The page stores no report; History is local to the current browser session.</div> ## What the tool answers The checker answers which catalogued services are suggested by public TXT verification records and which mail senders an SPF record names. Its conclusion is deliberately narrower than an ownership or security claim. A displayed provider, product, name or passing check means that the listed public evidence matched a documented rule at the observation time. Every conclusion is paired with evidence. The opening verdict is a summary for orientation, while Findings contains the actionable interpretation and the later result sections retain the underlying records, addresses, fields or names. If a conclusion matters operationally, verify that evidence through an authoritative account or an independent standards-aware client before changing production. ## Inputs ### Accepted source Enter a domain for a public TXT lookup, or paste TXT records for local analysis. Text containing a verification-token separator, quotes or multiple lines is interpreted as record material. The parser separates service verification patterns from SPF sender clues. Neither kind proves an active account or contractual relationship. Text files are read in the browser. The resulting input follows the same classification rules as the field; reading a file locally does not make a domain or public-IP lookup offline. Cleanup keeps an already accepted record intact and otherwise tries unwrapping a single-line address. Unusable text remains visible for correction. ### When work runs Domain input runs after a 600-millisecond typing pause. Enter runs it immediately; pasted records run immediately. Drops and page-wide paste use the same input loader. Leaving the field applies cleanup and reruns only when cleanup changes the text. Each edit aborts the previous request and increments a generation marker. A slower old response therefore cannot replace a newer result, and clearing the source immediately clears copyable output. The opening input uses the same parser and processing path as a replacement. The labelled live default sends the same requests as another domain. ## Reading the result ### Verdict and privacy The verdict states what the available evidence supports and uses pass, check, fail or informational status consistently. Pass means the bounded rule succeeded. Check means a human should confirm context. Fail means a concrete operational rule was violated. Info describes a limitation, absence or neutral fact and must not be promoted into success or failure by an automated reader. Two privacy lines distinguish browser-only work from live lookup work. The Checked line names the cleaned input and source mode. Copy result is hidden while work is pending, after an error and when input is empty, preventing a stale report from being exported as current. ### Findings and evidence Findings are ordered with failures first, then checks, informational notes and passes. Repeated passing details can fold into a disclosure so that exceptions remain visible. Each item states the observation and its consequence; any remediation is scoped to the evidence rather than presented as a universal configuration recipe. Evidence sections follow Findings and precede History. They are the audit trail for the verdict. A provider label derived from a catalog remains an inference, while a literal record or response field remains an observation. This distinction matters when signatures are incomplete, white-labelled or stale. ### History and handoffs History records intentional input replacements, including Break it examples and their repairs. Revert restores the prior input and runs it again, including live requests when applicable; Reset input returns to the value at the beginning of the recorded sequence. History is not monitoring, persistence or an account log. Check the rest carries the current input to other tools in Domains & hosting. Take it further sends the first recognised SPF record to the [SPF Checker](https://docs.tamperbox.dev/tools/spf-checker/) for its syntax and lookup-budget analysis. It is hidden when no SPF record is present. The initial handoff is a pasted record; any optional follow-up lookup follows that tool’s processing rules. Each receiving tool runs its own check; agreement is not guaranteed. Explicit tool links transfer the input through temporary browser `sessionStorage` and, when needed, a same-origin browser channel. The URL fragment contains a random transfer token, not the input. Transfers are accepted for less than one minute, consumed once, and bound to the destination path. The destination removes the token from its address. Ordinary documentation links and direct visits do not restore a previous input; if transfer storage is unavailable, the link still opens the tool. ## Method ### Validation and collection Before collection, the same domain validation runs in the browser and on the server boundary. Requests are restricted to supported public DNS names and HTTPS roots, redirects are bounded, response sizes are capped and abort signals are propagated. These limits make the observation reproducible and prevent an entered value from becoming an unrestricted network fetch. Use the input modes above to determine which requests run. DNS evidence comes from a public recursive view and can reflect cache state. Local classification cannot add observations absent from the supplied evidence. A server lookup is a fresh observation, not confirmation that cached or pasted evidence is still current. ### Classification rules TXT values are split without inventing record boundaries. The detector compares prefixes case-insensitively with a bounded catalog, groups matches by service, extracts SPF include and redirect domains, and keeps unrecognised token-shaped values separate. It never treats arbitrary prose as a service. [RFC 1035 section 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1) defines TXT as one or more character strings; joining and display preserve the evidence rather than interpreting it as authority. No confidence percentage is invented. When sources disagree, the disagreement is a finding. When a source is unavailable, the affected conclusion becomes informational or inconclusive rather than silently using a previous result. Catalog matches are exact bounded rules; unknown is a valid outcome. ### Ordering and export The renderer calculates all findings from the current observation before updating the verdict, chips, evidence and landing cards. Status priority is fail, check, info, pass. Stable secondary ordering keeps repeated runs readable without changing severity. The Markdown mirror and Copy result output preserve input, summary, findings and important evidence in text form. They do not embed secrets, browser state or the expanded educational cards. Agents should cite the observation time and limitation alongside any exported conclusion. ## Standards and conformance ### Applied specifications | Source | Rule used | Boundary | | --- | --- | --- | | [RFC 1035 section 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1) | TXT carries one or more character strings | The resolver supplies joined values; pasted lines are treated as observations | | [RFC 7208 section 4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) | SPF include and redirect cause DNS evaluation | The tool lists sender domains but does not evaluate authorization | | [RFC 1034 section 4.3.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.3.2) | Resolver answers can be cached and recursive | Results describe one public lookup, not every resolver | These references define the records and message semantics, not the provider catalogs. A catalog is product logic and can lag branding, acquisitions or custom deployments. Where a standard permits several valid configurations, the tool reports the observed form and avoids declaring one commercial pattern universally correct. ### Where conformance stops The checker is an observer, not an authoritative DNS server, browser, certificate monitor, mail receiver or provider control plane. It does not claim protocol conformance for the target. It applies selected validation and interpretation rules to bounded evidence and exposes the boundary where a fuller protocol operation would begin. The phrase “public” refers to the server's Internet view. Private split-horizon answers, authenticated dashboards and regional routing can differ. Cached answers can remain until TTL expiry, and HTTP intermediaries can transform what the origin sent. ## Finding reference ### Emitted findings | Finding | Severity | Meaning | Repair or next check | | --- | --- | --- | --- | | Recognised service | Pass | A public token matches the catalog | Confirm the token in that vendor's admin console | | Multiple tokens for one service | Check | Migration or stale verification may have left duplicates | Verify ownership, then remove only a vendor-confirmed obsolete token | | Mail sender | Info | SPF names a domain that may send mail | Use SPF Checker before changing authorization | | Not in the catalog | Info | The value resembles verification but has no known signature | Search the exact prefix in trusted vendor documentation | | No known services | Info | No catalog signature matched | Check CNAME and subdomain verification separately | Wording can include the observed name, count, provider or status. Automated consumers should use the supplied status and evidence rather than parsing the English title as a permanent identifier. A missing finding is not evidence that the corresponding external condition is absent when its source could not be collected. ### Status handling | Status | Consumer action | What not to infer | | --- | --- | --- | | Pass | Preserve the evidence and continue normal review | Permanent correctness, ownership or availability | | Check | Confirm intent and inspect the named evidence | Definite compromise or outage | | Fail | Prioritise the concrete broken rule and verify independently | That every user sees the same failure | | Info | Carry the limitation or neutral fact with the report | Success merely because no failure was emitted | ## Guide ### Verify independently Start with an authoritative or widely used command-line client. For DNS, use `dig` with the exact record type and compare every returned owner, target and TTL. Add `+trace` only when delegation matters; a trace and a recursive answer solve different questions. For HTTPS, use `curl -I --location https://host/` and retain each hop and response field. For certificates, use an established TLS client and a CT monitor you trust. Repeat from another network when geography or split routing could matter. Save the observation time and the original evidence before editing. After a DNS change, wait at least the prior TTL and then query both the intended authorities and independent recursive resolvers. ### Repair safely Do not delete an unfamiliar record or reroute a public name merely because a catalog labels it. First identify the owning service, deployment repository or provider account. Confirm whether the item is current, a migration remnant, a failover path or a delegated responsibility. Make the smallest reversible change, keep the prior value, and have a rollback trigger. Re-run this page after propagation, then verify the user-visible service. A clean public lookup cannot prove application health. Conversely, an informational unknown does not require a speculative change. ### Diagnose conflicting evidence When two signals disagree, ask whether they describe different layers: apex versus www, resolver cache versus authority, CDN edge versus origin, entered host versus redirected host, or certificate history versus current DNS. Compare literal evidence before comparing labels. The disagreement itself often reveals a migration or intermediary. If a lookup fails, preserve the error and retry once. Repeated timeouts are not equivalent to empty data. Use the specialist tool linked by the finding for deeper parsing rather than converting an inconclusive aggregate result into a failure. ### Break it and heal it Result cards name the recognised service and SPF sender clues and count records and unrecognised tokens. These values describe the supplied records, not verified accounts or a complete software inventory. Multiple tokens can be legitimate; confirm each one with its service owner before removal. The Break it controls create documented edge cases from the visitor's own input or a reserved fixture. They are teaching states, not scans. Heal it restores a safe derived value when the repair is deterministic. Revert remains available when several changes have been made. Use these cases to learn how invalid, missing, mixed or stale evidence appears before diagnosing production. The control never edits DNS, hosting, certificates or provider accounts. ## Worked example The live default is `mozilla.org`. At the comparison point it populated recognised services, SPF senders and unknown-token evidence, making the whole report inspectable. The records can change; the example is selected for structural coverage, not as an enduring claim about Mozilla. Read the example from verdict to Findings, then compare the literal evidence. Open one Break it case and use Heal it or Revert. Finally, replace the default with a domain you are authorised to assess. This sequence demonstrates both the successful path and the failure contract without implying that the named public domain endorses the tool. ## For agents Agents can discover the `saas_stack` operation through Tamperbox MCP. The browser page id `saas-stack` is not the operation name. The server operation and browser renderer can expose different fields; inspect the operation schema before supplying arguments. Preserve the result's distinction between observed evidence, catalog inference and limitation. State whether the run was live or pasted, include the cleaned target and observation time, and never turn “not found” into “does not exist” unless the method truly establishes that condition. Choose a specialist operation when the task is narrow. Use this page's report when its combined view or educational findings add value. Do not pass credentials, private hostnames or customer data into a public lookup. If a repair would change production, present the exact evidence, expected effect, propagation window and rollback before acting. Machine readers should branch on status and structured fields where available, not English punctuation. Treat network and parse errors as inconclusive. Re-run after a meaningful interval rather than repeatedly polling a third-party source. ## Limits The catalog is intentionally finite. Services may verify with CNAME, files, meta tags, delegated subdomains or private account state, none of which a bare-domain TXT lookup sees. Tokens can remain after cancellation or be copied, so a match is a clue rather than proof of ownership, billing, activity or compromise. All outputs are point-in-time observations. Resolver caching, negative caching, anycast, geo steering, redirects and intermittent upstream failures can change a later run. The service does not retain a monitoring history or notify on change. Local History is an interaction aid, not durable evidence. No result grants permission to probe a target or modify it. Use authorised accounts and owner-approved procedures for deeper checks. Where business, security or legal decisions depend on attribution, obtain confirmation from the responsible provider or domain operator. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034), Domain Names — Concepts and Facilities, especially [section 4.3.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.3.2) for resolver behavior. - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035), Domain Names — Implementation and Specification, especially [section 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1) for resource-record types and classes. - [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110), HTTP Semantics, especially [section 3.7](https://www.rfc-editor.org/rfc/rfc9110#section-3.7) for intermediaries and [section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) for status codes when HTTP evidence is collected. - [Tamperbox SaaS Stack Detector](https://tamperbox.dev/saas-stack), the interactive tool and current Markdown mirror. --- # Security and privacy Understand where code runs, where operation inputs go, and which conclusions Tamperbox evidence can support. Canonical: https://docs.tamperbox.dev/reference/security/ Updated: 2026-10-19 Applies to: MCP 0.2.0 Outputs: A data-handling decision for a planned Tamperbox task Limitations: Hosting, proxy, and model-provider logging policies are separate from Tamperbox package behavior. ## Code isolation Submitted code runs in a fresh QuickJS WebAssembly environment inside a worker thread. The guest has no general network client. Only allowlisted calls to documented Tamperbox API routes cross the host boundary. ## Data path Code and embedded inputs are visible to the MCP client and model provider. When `execute` calls an operation, its request input is sent to the configured Tamperbox API. A remotely hosted MCP service also receives the submitted code and embedded values. Use synthetic examples for evaluation. Prefer browser-local tools for sensitive material that should not leave the device. ## Evidence boundaries - JWT decoding does not verify signature authenticity or issuer trust. - DNS evidence does not prove email delivery or mailbox existence. A published DKIM key, for example, does not prove any message is signed with it ([why](https://docs.tamperbox.dev/tools/dkim-checker/#limits)). - HTTP headers do not establish the complete security of a site, and one TLS handshake from one location does not establish what every client negotiates ([why](https://docs.tamperbox.dev/tools/ssl-checker/#limits)). - A redirect trace or a CORS preflight sent from the service is one observation from one place: cookies, client addresses and firewalls can make a visitor's browser see something else ([why](https://docs.tamperbox.dev/tools/cors-tester/#limits)). - A decoded JWT is readable, not trusted; a signature match proves only that the supplied key verifies those bytes ([why](https://docs.tamperbox.dev/tools/jwt/#limits)). - A failed probe is not the same as a negative result. - Caller-context checks can observe a proxy, shared gateway, or MCP host. ## Unsupported authority Tamperbox does not authenticate to DNS accounts, send mail, publish records, or mutate third-party services. It inspects and transforms within the documented API contract. Report security issues through the process in the [Tamperbox MCP security policy](https://github.com/oceanrescue/tamperbox-mcp/blob/main/SECURITY.md). --- # Security Headers Checker How the security headers checker fetches a page or reads pasted headers, the six headers it scores and every rule behind the grade, what each finding means, and how to fix and verify each header. Canonical: https://docs.tamperbox.dev/tools/security-headers/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public website on port 80 or 443, or response headers copied from curl -I or a browser's network panel Outputs: A grade from A+ to F with the points out of 6, chips, findings worst first with the value received and the line to send instead, a configuration snippet in six server syntaxes, and the response headers as received Limitations: One response from one address at one moment is graded; other pages, error responses and signed-in views can differ; HSTS preload lists and the non-script directives of a Content-Security-Policy are not evaluated; A grade is configuration evidence, not a security assessment of the site The tool page is [tamperbox.dev/security-headers](https://tamperbox.dev/security-headers). It opens by grading `mozilla.org` live, answers in one sentence with a letter and the headers that cost points, and lists every header under it. This page is the long version: what our server requests, every rule behind the grade, what each finding means, and how to send each header and confirm it. <div class="tb-callout"><strong>Where processing happens:</strong> a website is sent to the Tamperbox server, which requests the page itself, follows up to 10 redirects, removes cookie values and returns the final response's headers. Pasted headers are graded in your browser and never uploaded. History and tool-to-tool transfers remain in the browser; see Browser transfers below.</div> ## What the tool answers Four questions, in the order the result answers them: 1. **How well does this response protect visitors?** A letter from A+ to F, from six headers worth one point each. 2. **Which headers cost points, and why?** Every header the grade reads, worst first, with the value received and what that value lets an attacker do. 3. **What exactly should be sent instead?** The line for each header that missed a point, and the whole set written for nginx, Apache, Caddy, a `_headers` file, IIS or Express. 4. **What else does the response say about the server?** Version numbers in `Server` and `X-Powered-By`, obsolete headers, and Cross-Origin-Opener-Policy, which decide an A+ without changing the letter. The verdict sentence names the grade and the headers that cost the most. The chips count the headers doing their job, the ones missing or not working, the weak ones and any versions announced. ## Inputs The field takes either form. What decides it is the first line: a status line such as `HTTP/2 200`, or a `name: value` header line, is read as pasted headers; anything else is read as an address. | Input | What happens | Where | | --- | --- | --- | | `example.com` or `https://example.com/page` | Checked when you stop typing or on Enter, as `https://` when no scheme is given | Our server | | `http://example.com/` | Checked from `http://`, so a missing redirect to HTTPS is graded | Our server | | Output of `curl -sI` or `curl -sIL` | Graded at once; only the last response in the paste counts | Your browser | | A `.txt` or `.http` file up to 256 KiB | Read into the field and graded like a paste | Your browser | ### A website The address is cleaned before it is checked: a pasted full link keeps its scheme, host and path, quotes and trailing punctuation are dropped, and text that is not an address stays as pasted so the error explains it. The parser refuses, with a message in the field, an address with spaces, a scheme other than `http` or `https`, an IP address, a host without a top-level domain, a port other than 80 or 443, and a user name or password; the last two offer a repair under Heal it. The fragment is dropped. Our server applies the same rules again, requires the host to resolve only to public addresses, and gives the whole check 45 seconds. It sends one `GET` per hop as `TamperboxBot/1.0`, without cookies, follows at most 10 redirects and grades the response that is not a redirect. `Set-Cookie` values are replaced by `[redacted:n]` before the headers reach your browser. ### Pasted headers The paste may hold several responses, as `curl -sIL` prints them; each status line starts a new one and only the last is graded. Header names are compared without regard to case. Pasted headers are graded as if they arrived over HTTPS, because a paste carries no transport. Text without a single header line is refused with "No headers found". ## Reading the result ### Verdict and chips The line reads `Grade B.` followed by the gaps that cost the most: up to two header titles, or the first and "n more headers missing or not working", then a version leak if there is one. Under it, the points and where they came from: "5 of 6 points, from https://www.example.com/ after 1 redirect", with the status when the final response was 400 or above. ### Findings Every header the grade reads, one row each, worst first: failures, then warnings, then notes, then passes; within a status, the header that lost a whole point comes before one that lost half. Each row shows the header name, its badge, a title, what the value means, the value received or "Not sent", and, when the header missed a point, an **Add** or **Send instead** line with a Copy button. Two or more passes fold into one "n checks passed" line. Version leaks and the headers that do not count (Cross-Origin-Opener-Policy, X-XSS-Protection, Public-Key-Pins, Expect-CT) sit in the same list. ### Grade The letter, the points, and six slots, one per scored header: Set, Weak, Not working or Missing, with a two-step meter. Each slot jumps to its row in Findings, opening the folded passes when needed. ### Add the missing headers One configuration block for every scored header that missed a point and has a suggested line, in the server syntax you pick. The note under it says where the block goes and warns when it contains a Content-Security-Policy, which enforces as soon as it is published. ### Response headers, History and Take it further The full response as received, folded, with the scored headers marked "counts", "weak" or "not working". History lists every Break it and Heal it change with Revert and Reset input. Take it further hands the host the headers came from to the other checks in this category; see [Guide](#guide). ### Browser transfers Explicit tool links temporarily place the transferred input in browser `sessionStorage`. The URL fragment carries a random token, not the input. The receiving page accepts that token once, for its destination path and for less than one minute, then removes it from the address. A same-origin browser channel can complete a transfer into another tab. Ordinary documentation links do not transfer input. When browser storage is unavailable, navigation still works but the input may need to be pasted again. ## Method The grade is computed by `gradeSecurityHeaders` from one list of headers: the final response for an address, the last response of a paste. Six slots score 0, 0.5 or 1. The rules run in the order below; the first rule that matches a slot decides it. ### Strict-Transport-Security [RFC 6797, section 8.1](https://www.rfc-editor.org/rfc/rfc6797#section-8.1) decides two rules: "If an HTTP response is received over insecure transport, the UA MUST ignore any present STS header field(s)", and with more than one header "the UA MUST process only the first such header field". The `max-age` directive is required by [section 6.1.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1.1), where zero means the host is no longer a known HSTS host. | Condition | Points | Finding | | --- | --- | --- | | Final address is `http://` | 0 | Served over plain HTTP | | No header | 0 | No HSTS response header | | `max-age` missing, repeated or not a whole number | 0 | HSTS cannot be read | | `max-age=0` | 0 | HSTS switched off (max-age=0) | | Below 31536000 seconds | 0.5 | HSTS for _duration_ | | One year or more | 1 | HSTS for _duration_, with subdomains when `includeSubDomains` is present | A second header adds the note "Sent more than once: browsers read only the first." `includeSubDomains` is described but not required, and `preload` is not scored. Unknown directives do not change the score. ### Content-Security-Policy Only the enforced header scores. The first policy is parsed; a repeated directive keeps its first occurrence. Scripts are governed by [`script-src`](https://www.w3.org/TR/CSP3/#directive-script-src), falling back to [`default-src`](https://www.w3.org/TR/CSP3/#directive-default-src). | Condition | Points | Finding | | --- | --- | --- | | Only [Content-Security-Policy-Report-Only](https://www.w3.org/TR/CSP3/#cspro-header) | 0 | Content-Security-Policy is report-only | | No policy | 0 | No Content-Security-Policy | | Neither `script-src` nor `default-src` | 0.5 | CSP does not restrict scripts | | `'unsafe-inline'` without a nonce, a hash or `'strict-dynamic'` | 0.5 | CSP allows inline scripts ('unsafe-inline') | | `*`, `http:`, `https:` or `data:` without `'strict-dynamic'` | 0.5 | CSP allows scripts from any host | | Anything else | 1 | CSP restricts scripts | `'unsafe-eval'` is mentioned in the passing finding but costs nothing. Several enforced headers add a note, because every policy is enforced and the strictest combination applies ([CSP Level 3, multiple policies](https://www.w3.org/TR/CSP3/#multiple-policies)). ### Framing and content sniffing [`frame-ancestors`](https://www.w3.org/TR/CSP3/#directive-frame-ancestors) in the enforced policy earns the framing point whatever X-Frame-Options says. Without it, X-Frame-Options is read as [RFC 7034, section 2.1](https://www.rfc-editor.org/rfc/rfc7034#section-2.1) defines it: `DENY` or `SAMEORIGIN` scores 1 ("Never shown in a frame", "Framed only by this site"), `ALLOW-FROM` scores 0.5 because current browsers ignore it, any other value scores 0, and no header scores 0 ("Any site can frame this page"). X-Content-Type-Options scores 1 only when its value is `nosniff`, compared without case, as the [Fetch Standard](https://fetch.spec.whatwg.org/#x-content-type-options-header) defines it. Any other value scores 0 with the value in the title; no header scores 0. ### Referrer-Policy and Permissions-Policy All Referrer-Policy values are joined and the last recognised token wins, as [Referrer Policy, parsing the header](https://www.w3.org/TR/referrer-policy/#parse-referrer-policy-from-header) specifies. The [policies](https://www.w3.org/TR/referrer-policy/#referrer-policies) `no-referrer`, `same-origin`, `strict-origin`, `strict-origin-when-cross-origin`, `origin` and `origin-when-cross-origin` score 1. `no-referrer-when-downgrade` and unrecognised values score 0.5, `unsafe-url` scores 0. No header scores 0.5, because current browsers default to `strict-origin-when-cross-origin`. Any [Permissions-Policy](https://www.w3.org/TR/permissions-policy/#permissions-policy-http-header-field) header scores 1; the tool counts the features it lists but does not judge them. The old `Feature-Policy` name alone scores 0.5. Neither scores 0. ### Letter, A+ and leaks 6 points is A, 5 or 5.5 is B, 4 or 4.5 is C, 3 or 3.5 is D, 2 or 2.5 is E, below 2 is F. A+ needs every slot at 1, [Cross-Origin-Opener-Policy](https://html.spec.whatwg.org/multipage/browsers.html#cross-origin-opener-policies) set to `same-origin` or `same-origin-allow-popups`, and no leak. A leak is a `Server` value containing a digit, or any `X-Powered-By`, `X-AspNet-Version`, `X-AspNetMvc-Version` or `X-Generator`. Leaks block A+ and never lower the letter. ## Standards and conformance | Specification | Sections used | How the tool applies it | Where it stops | | --- | --- | --- | --- | | [RFC 6797](https://www.rfc-editor.org/rfc/rfc6797) HSTS, Proposed Standard | [6.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1), [6.1.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1.1), [7.2](https://www.rfc-editor.org/rfc/rfc6797#section-7.2), [8.1](https://www.rfc-editor.org/rfc/rfc6797#section-8.1) | Parses directives locally; ignores the header on `http://`; reads only the first header | Preload lists and stored policies are not consulted; a one-year floor is a grading choice, not an RFC rule | | [CSP Level 3](https://www.w3.org/TR/CSP3/), W3C Working Draft | `script-src`, `default-src`, `frame-ancestors`, Report-Only, multiple policies | Reads the script source list of the first enforced policy | Style, image, connect, form and other directives, nonce validity and `report-to` are not evaluated | | [RFC 7034](https://www.rfc-editor.org/rfc/rfc7034) X-Frame-Options, Informational | [2.1](https://www.rfc-editor.org/rfc/rfc7034#section-2.1) | Accepts `DENY` and `SAMEORIGIN`; half a point for `ALLOW-FROM` | Superseded in practice by `frame-ancestors`, which takes precedence | | [Fetch Standard](https://fetch.spec.whatwg.org/#x-content-type-options-header) | X-Content-Type-Options | Exact `nosniff`, case-insensitive | Does not check that each response carries a correct Content-Type | | [Referrer Policy](https://www.w3.org/TR/referrer-policy/) | Policies, header parsing | Last recognised token wins | Per-element `referrerpolicy` attributes and `meta` tags are not seen | | [Permissions Policy](https://www.w3.org/TR/permissions-policy/) | The HTTP header field | Presence only | Feature allowlists are not judged | | [HTML Standard](https://html.spec.whatwg.org/multipage/browsers.html#cross-origin-opener-policies) | Cross-origin opener policies | `same-origin` or `same-origin-allow-popups` for A+ | COEP and CORP are not graded | Pasted headers are combined as [RFC 9110, section 5.3](https://www.rfc-editor.org/rfc/rfc9110#section-5.3) allows for list fields: Referrer-Policy values are joined with commas, while HSTS and CSP read the first field line. [RFC 7469](https://www.rfc-editor.org/rfc/rfc7469) (key pinning) and [RFC 9163](https://www.rfc-editor.org/rfc/rfc9163) (Expect-CT) are reported only as obsolete headers. ## Finding reference ### Scored headers that fail | Finding | Points | Rule | Fix | | --- | --- | --- | --- | | Served over plain HTTP | 0 | [RFC 6797 §8.1](https://www.rfc-editor.org/rfc/rfc6797#section-8.1) | Redirect to HTTPS, then send HSTS there | | No HSTS response header | 0 | [RFC 6797 §6.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1) | `max-age=31536000` | | HSTS cannot be read | 0 | [RFC 6797 §6.1.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1.1) | One numeric `max-age` | | HSTS switched off (max-age=0) | 0 | [RFC 6797 §6.1.1](https://www.rfc-editor.org/rfc/rfc6797#section-6.1.1) | `max-age=31536000` | | No Content-Security-Policy | 0 | [CSP3 script-src](https://www.w3.org/TR/CSP3/#directive-script-src) | Starter policy, tested as Report-Only | | Content-Security-Policy is report-only | 0 | [CSP3 Report-Only](https://www.w3.org/TR/CSP3/#cspro-header) | Send the same policy enforced | | No X-Content-Type-Options, or a wrong value | 0 | [Fetch](https://fetch.spec.whatwg.org/#x-content-type-options-header) | `nosniff` | | Any site can frame this page, or a wrong X-Frame-Options | 0 | [RFC 7034 §2.1](https://www.rfc-editor.org/rfc/rfc7034#section-2.1) | `SAMEORIGIN` or `frame-ancestors` | | Referrer-Policy is unsafe-url | 0 | [Referrer Policy](https://www.w3.org/TR/referrer-policy/#referrer-policies) | `strict-origin-when-cross-origin` | | No Permissions-Policy | 0 | [Permissions Policy](https://www.w3.org/TR/permissions-policy/#permissions-policy-http-header-field) | `camera=(), microphone=(), geolocation=()` | ### Scored headers that are weak | Finding | Points | Fix | | --- | --- | --- | | HSTS for _duration_ (under a year) | 0.5 | Raise `max-age` to 31536000 or more | | CSP does not restrict scripts | 0.5 | Add `script-src` or `default-src` | | CSP allows inline scripts ('unsafe-inline') | 0.5 | Nonces or hashes | | CSP allows scripts from any host | 0.5 | List the script hosts | | X-Frame-Options ALLOW-FROM is ignored | 0.5 | `frame-ancestors` with the origin | | No Referrer-Policy, Full URLs go to other sites, or an unknown value | 0.5 | `strict-origin-when-cross-origin` | | Feature-Policy is the old name | 0.5 | Send Permissions-Policy | ### Not scored | Finding | Status | Meaning | | --- | --- | --- | | Server names its software version, x-powered-by names the framework | Check | Blocks A+; hide the version at the server or proxy | | No Cross-Origin-Opener-Policy, or another value | Note | Needed for A+; `same-origin` | | Public-Key-Pins is obsolete and risky | Check | Remove it | | X-XSS-Protection is obsolete, Expect-CT is obsolete | Note | Remove them, or send `X-XSS-Protection: 0` | ## Guide ### Send the headers from the right layer Add the block from **Add the missing headers** where every response passes: the CDN or reverse proxy when there is one, otherwise the web server's site block. In nginx, `add_header` inside a `location` replaces every `add_header` inherited from the server block, which is why a header often appears on the home page and not on other routes; `always` makes it apply to error responses too. In Apache, use `Header always set` with `mod_headers`. ### Roll out a Content-Security-Policy 1. Send the starter policy as `Content-Security-Policy-Report-Only` with a `report-to` endpoint. 2. Read the violations for a release cycle; add the hosts the site really loads from, and replace inline scripts with nonces or hashes. 3. Rename the header to `Content-Security-Policy` and grade again: the slot should read "CSP restricts scripts". ### Raise HSTS safely Start with a short `max-age` only if you are unsure every page works over HTTPS, then raise it to `31536000`. Add `includeSubDomains` after every subdomain serves HTTPS; once set, a subdomain without a valid certificate becomes unreachable for visitors, with no click-through ([RFC 6797, section 12.1](https://www.rfc-editor.org/rfc/rfc6797#section-12.1)). ### Confirm outside Tamperbox `curl -sI https://example.com/` prints the headers of one response; `curl -sIL http://example.com/` follows redirects so the last block is what the tool grades. Paste either into the tool to grade it locally. Check an error page and a static file too: `curl -sI https://example.com/missing` and the address of a script or image. ### Break it and Heal it | Break it | Built from | Shows | | --- | --- | --- | | No security headers | Your headers without any security header | F, every slot missing | | Inline scripts allowed | Your headers with `script-src 'self' 'unsafe-inline'` | The half-point CSP rule | | HSTS for five minutes | `max-age=300` | The duration rule | | Policy only reports | Your policy renamed to Report-Only | Zero for an unenforced policy | | Versions announced | `Server: Apache/2.4.49`, `X-Powered-By: PHP/7.4.3` | Leaks that block A+ | | Plain HTTP site | A reserved sample host on `http://` | Served over plain HTTP | Heal it adds every suggested line and drops version headers for a paste ("Add n headers"), or, for a website, loads its headers with the fixes applied ("Preview the fixed headers") so you see the grade they would get; nothing changes on the site. ### Take it further When a website was fetched over HTTPS, the result hands its final host on: to the [SSL checker](https://tamperbox.dev/ssl-checker) when HSTS is set, since HSTS turns certificate errors into hard failures; the final page to the [mixed content checker](https://tamperbox.dev/mixed-content-checker); and, when redirects moved to another host, that host to the [DANE checker](https://tamperbox.dev/dane-checker) as `host:443` and to the [post-quantum checker](https://tamperbox.dev/post-quantum-checker). Pasted headers and reserved sample hosts show none. ## Worked example The page opens on `mozilla.org`, checked live. It was chosen from a comparison of real runs because its response fills every block of the result, but it is someone else's site and its headers change, so read the result in this order rather than expecting fixed values. ### The opening result 1. **Score line.** It names the final address and the redirects that led there; `mozilla.org` moves to its `www` host, so the graded response is not the one you typed. 2. **Verdict and Findings.** The letter, then the headers that cost points, worst first: a header that lost its whole point comes before one that lost half. Open each row for the value received and the line to send instead. 3. **Grade.** The six slots show at a glance which headers are set, weak or missing. 4. **Add the missing headers.** When a header with a suggested line missed its point, the block writes it in your server's syntax. 5. **Heal it.** "Preview the fixed headers" loads the same response with those lines applied, so you see the grade they would earn; Revert brings the live result back. 6. **Take it further.** Because the response came over HTTPS after a move to another host, the final host and page are handed to the other checks in the category. ### A fixed contrast Break it builds on whatever is in the box. "No security headers" removes every security header from the opening response and turns it into an F with six lines to add; the repair under Heal it puts them back. `www.harbor-supply.example` is a reserved sample host graded locally, with fixed, synthetic headers, for a result that never changes. ## For agents Over [Tamperbox MCP](https://docs.tamperbox.dev/mcp/connect/), the `security_headers` operation takes a URL, fetches it with the same server path and returns the fetch evidence and the report (grade, score, items, leaks). `security_headers_analyze` grades pasted headers without any network request and, given a `server` such as `nginx`, returns a snippet that transcribes the supplied headers. Keep the warnings when you report a result: the grade is configuration evidence for one response, not a vulnerability assessment; a suggested Content-Security-Policy enforces immediately and must be tested as Report-Only; and `includeSubDomains` can lock out subdomains without HTTPS. ## Limits - One response, from one location, at one moment. Other routes, error pages, static files, signed-in views and other regions of a CDN can send different headers. - HSTS is read from the header only: browser preload lists, including whole-TLD entries such as `.dev`, and policies stored from earlier visits are not consulted. - Only the script rules of a policy are judged. A policy can earn its point and still allow risky styles, images, forms or connections. - Permissions-Policy scores on presence; its allowlists are not reviewed. - Pasted headers are assumed to have arrived over HTTPS, and only the last pasted response counts. - The letter is this tool's scale. Other graders weigh headers differently, so letters are not comparable across tools. ## References - [RFC 6797: HTTP Strict Transport Security](https://www.rfc-editor.org/rfc/rfc6797), sections 6.1, 6.1.1, 7.2, 8.1 and 12.1. Proposed Standard; not obsoleted. - [Content Security Policy Level 3](https://www.w3.org/TR/CSP3/): script-src, default-src, frame-ancestors, the Report-Only header, multiple policies. W3C Working Draft. - [RFC 7034: HTTP Header Field X-Frame-Options](https://www.rfc-editor.org/rfc/rfc7034), section 2.1. Informational. - [Fetch Standard: X-Content-Type-Options](https://fetch.spec.whatwg.org/#x-content-type-options-header). Living Standard. - [Referrer Policy](https://www.w3.org/TR/referrer-policy/): policies and header parsing. W3C Candidate Recommendation. - [Permissions Policy](https://www.w3.org/TR/permissions-policy/): the HTTP header field. W3C Working Draft. - [HTML Standard: cross-origin opener policies](https://html.spec.whatwg.org/multipage/browsers.html#cross-origin-opener-policies). Living Standard. - [RFC 9110: HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110#section-5.3), section 5.3, field order. Internet Standard. - [RFC 7469: Public Key Pinning](https://www.rfc-editor.org/rfc/rfc7469) and [RFC 9163: Expect-CT](https://www.rfc-editor.org/rfc/rfc9163), cited only to mark the headers obsolete. --- # security.txt Checker How the security.txt checker fetches /.well-known/security.txt or reads a pasted file, every RFC 9116 rule it applies, what each finding means for a researcher, and how to fix and verify it. Canonical: https://docs.tamperbox.dev/tools/security-txt-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public host name, or the text of a security.txt file to paste Outputs: A verdict, findings worst first, the file read as a researcher reads it, the Expires date on a time axis, the file listing with problem lines marked, and a corrected file or a draft form Limitations: Only /.well-known/security.txt is requested; OpenPGP signatures are separated but not verified; validity is syntax and rules, not proof that anyone reads the Contact The tool page is [tamperbox.dev/security-txt-checker](https://tamperbox.dev/security-txt-checker). It opens by checking `google.com` live, answers in one sentence, and shows the file the way a security researcher reads it. This page is the long version: what our server requests, every rule the page applies with the section of [RFC 9116](https://www.rfc-editor.org/rfc/rfc9116) behind it, what each finding means, and how to fix and confirm it. <div class="tb-callout"><strong>Where processing happens:</strong> a host name is sent to the Tamperbox server, which requests https://host/.well-known/security.txt once, follows up to five HTTPS redirects, reads at most 64 KiB and returns the file with its status and media type. A pasted or dropped file is read in your browser and never uploaded. The same parser judges both. History and tool-to-tool transfers remain in the browser; see Browser transfers below.</div> ## What the tool answers The questions come in the order a researcher who just found a vulnerability would ask them: 1. **Is there a file where the standard says to look?** The address, the HTTP status, the media type, and whether the answer is a text file or the site's web page. 2. **Is it valid under RFC 9116?** A Contact, exactly one Expires, well-formed lines and absolute URIs. 3. **Where do I send the report, and how?** The contacts in order of preference, the key to encrypt with, the policy to read first, and the languages accepted. 4. **Is it still current?** The Expires date against the moment of the check and the one-year recommendation. 5. **Is this the official copy?** Whether a Canonical line names the address the file was actually served from. 6. **What should the file say instead?** A corrected file, or, when there is no file, a short form that writes one. ## Inputs ### A host name `example.com` or `www.example.com`. The check runs when you stop typing, or on Enter. The page refuses, with a message under the field, a value with spaces, a scheme other than `http` or `https`, an IP address, a host without a top-level domain, a port other than 80 or 443 and credentials in an address; the last two offer a repair. Our server refuses private hosts and addresses with "Use a public domain name, not a private host or IP address." ### A pasted or dropped file Text is read as a file when it has a line break, or when its first line looks like a field (`Contact: …`), a comment (`#`) or a PGP header, and does not start with `http://` or `https://`. A dropped file is read the same way, up to 64 KiB. A missing final line break is added before checking, because clipboards usually drop it. ### What the page does to pasted text | You paste | The field keeps | Why | | --- | --- | --- | | `https://github.com/oceanrescue/` | `github.com` | A full address is reduced to its host by the shared paste cleanup | | `security@example.com` or `mailto:` | `example.com` | The domain of an email address | | `"example.com"` or `<example.com>` | `example.com` | Quotes, brackets and trailing punctuation dropped | | A security.txt file | The file, unchanged | It is read locally | | Text that fits nothing | The text as pasted | The parser's own error explains it | Cleaning runs on paste, drop, handoff, Enter and leaving the field; it never rewrites what you type, and never touches Break it or Heal it loads. ## Reading the result ### Verdict and chips The verdict names the outcome first: "Valid security.txt.", "Not valid:" followed by the worst problem, or "No security.txt." when the address did not return a text file. The detail line says where the file came from, including the number of redirects. Chips count problems and things to check, the contacts, and the days to expiry; each scrolls to its evidence. Two privacy items say where this input went. ### Findings Directly under the verdict, worst first. Errors make the file invalid; warnings do not. A finding tied to a line has a Show line button that highlights it in the file listing. ### What a researcher sees The fields in the order a researcher uses them: Report to, Encrypt with, Read first, Thanks, Languages (with names), Canonical, Hiring, Advisories and Other fields. A missing field says what its absence means. Every value has a Copy button; a value on an error line carries a Problem badge. ### Expiry, the file and the corrected file The Expires date on a time axis with the moment of the check and the one-year mark. The file as served, numbered, with problem lines marked. Under it, the corrected file to copy or download, or the draft form when there was no file. ### History and Take it further History logs every Break it and Heal it load with Revert and Reset input. Take it further carries values from the file into other security tools: the host serving the Encryption key to the certificate checker, the first `https` Contact to the security headers checker, the first `https` Policy to the mixed content checker, and, after a redirect, the host that served the file to the certificate checker. Reserved example names are never offered. ### Browser transfers Explicit tool links temporarily place the transferred input in browser `sessionStorage`. The URL fragment carries a random token, not the input. The receiving page accepts that token once, for its destination path and for less than one minute, then removes it from the address. A same-origin browser channel can complete a transfer into another tab. Ordinary documentation links do not transfer input. When browser storage is unavailable, navigation still works but the input may need to be pasted again. ## Method ### What our server requests One `GET https://host/.well-known/security.txt`, the location [RFC 9116 section 3](https://www.rfc-editor.org/rfc/rfc9116#section-3) defines: for web-based services the file MUST be placed under the `/.well-known/` path. Redirects are followed up to five hops; each target must be `https://`, a loop stops the check, and a sixth redirect stops it with "Too many security.txt redirects." The body is read up to 64 KiB and decoded as strict UTF-8. The legacy `/security.txt` at the root, which section 3 allows only for legacy compatibility, as a copy or as a redirect to the /.well-known/ file, is not requested. ### Response rules | Rule | Finding | Severity | Source | | --- | --- | --- | --- | | Final status is 200 | Not served | Error | [RFC 9116 section 3](https://www.rfc-editor.org/rfc/rfc9116#section-3) | | `Content-Type` is `text/plain`, and a charset, if present, is `utf-8` | Wrong media type | Error | [section 3](https://www.rfc-editor.org/rfc/rfc9116#section-3) | | Body is valid UTF-8 | Not UTF-8 | Error | [section 4](https://www.rfc-editor.org/rfc/rfc9116#section-4) | | Body fits in 64 KiB | Larger than 64 KiB | Error | Tool limit | Section 3 states the file "MUST have a Content-Type of 'text/plain' with the default charset parameter set to 'utf-8'". When the status is not 200, or the answer is HTML, the page treats the site as having no file and shows the draft form instead of a field report. ### Line syntax Blank lines and lines starting with `#` are skipped ([section 2.1](https://www.rfc-editor.org/rfc/rfc9116#section-2.1)). Every other line must be a field name, a colon, a space and a non-empty value without control characters, as in the ABNF of [section 4](https://www.rfc-editor.org/rfc/rfc9116#section-4); otherwise it is "Not a field line". Field names are case-insensitive ([section 2](https://www.rfc-editor.org/rfc/rfc9116#section-2)). A fetched file must end with a line break, CRLF or LF ([section 2.2](https://www.rfc-editor.org/rfc/rfc9116#section-2.2); "Last line has no line break"). Unknown fields are listed without an error, as [section 2.4](https://www.rfc-editor.org/rfc/rfc9116#section-2.4) allows extensions. ### Field rules | Rule | Finding | Source | | --- | --- | --- | | At least one Contact | No way to report | [section 2.5.3](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.3): "This field MUST always be present" | | Exactly one Expires | No Expires date / Expires appears more than once | [section 2.5.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.5): "MUST always be present and MUST NOT appear more than once" | | Expires is RFC 3339 | Expires is not a date | [section 2.5.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.5), [RFC 3339 section 5.6](https://www.rfc-editor.org/rfc/rfc3339#section-5.6) | | Expires is in the future | The file has expired (error) | [section 2.5.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.5) | | Expires at most 366 days ahead | Expires more than a year ahead (warning) | [section 2.5.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.5): a value less than a year ahead is RECOMMENDED | | URIs are absolute | Not an absolute URI | [section 2.5.3](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.3), [section 4](https://www.rfc-editor.org/rfc/rfc9116#section-4), [RFC 3986 section 4.3](https://www.rfc-editor.org/rfc/rfc3986#section-4.3) | | Web URIs use `https` | A web address uses http:// | [section 2.5.3](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.3) and siblings: "MUST begin with 'https://'" | | One Preferred-Languages | Preferred-Languages repeated | [section 2.5.8](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.8) | | Valid language tags | Not a language tag | [section 2.5.8](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.8), [RFC 5646](https://www.rfc-editor.org/rfc/rfc5646) | | A Canonical matches the fetched URL | Canonical points elsewhere | [section 2.5.2](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.2) | The URI rule applies to Contact, Canonical, Encryption, Policy, Hiring and Acknowledgments. Dates are checked against the calendar, so `2027-02-30T00:00:00Z` and a bare `2027-03-01` both fail. Canonical is only compared for a fetched file. ### Signed files A file starting with `-----BEGIN PGP SIGNED MESSAGE-----` is split from its signature and dash-escaping is removed, as [RFC 9580 section 7](https://www.rfc-editor.org/rfc/rfc9580#section-7) describes the cleartext framework. A malformed envelope is "Broken signature block" (error). A well-formed one is "Signed, not verified here" (warning): [RFC 9116 section 2.3](https://www.rfc-editor.org/rfc/rfc9116#section-2.3) RECOMMENDS a digital signature, and verifying the signature is the reader's job. ### Heal it Each repair rewrites the file and checks it again: set Expires to 364 days after the check at midnight UTC; switch `http://` to `https://` in web fields; turn broken lines into comments; keep the first Preferred-Languages; point Canonical at the fetched URL; end the last line. A missing Contact is never invented. For a fetched file, a repair loads a corrected copy here; nothing changes on the site. ## Standards and conformance ### RFC 9116: A File Format to Aid in Security Vulnerability Disclosure Implemented: the location and media type of [section 3](https://www.rfc-editor.org/rfc/rfc9116#section-3); comments, line separators and the field rules of [sections 2.1 to 2.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5) for Contact, Expires, Encryption, Policy, Acknowledgments, Preferred-Languages, Canonical and Hiring; the ABNF of [section 4](https://www.rfc-editor.org/rfc/rfc9116#section-4) as one regular expression. All rules run in `public/lib/security-txt.js`, shared by the browser and the server, so a pasted file and a fetched one get the same report; the response rules run on the server only. CSAF lines (registered later in the IANA registry) are listed but not validated. ### Where the tool is stricter or more lenient | Point | RFC text | Tool | | --- | --- | --- | | Space after the colon | The ABNF of section 4 requires it (`fs SP`) | Requires the space and reports `Name:value` as a broken line | | Expires a year ahead | Less than a year is RECOMMENDED | Warning after 366 days, never an error | | Signature | Signing is RECOMMENDED | Absence is not a finding; presence is not verified | | Canonical | Lists every URI the file is served from | Checked only against the final fetched URL | | Legacy location | `/security.txt` may redirect | Not requested | | Size | No limit stated | 64 KiB read limit | The space rule follows the ABNF, so that the most common hand-written slip, `Contact:mailto:…`, is caught before a lenient reader guesses. ### RFC 3339, RFC 5646 and RFC 3986 Expires follows the `date-time` production of [RFC 3339 section 5.6](https://www.rfc-editor.org/rfc/rfc3339#section-5.6), including fractional seconds and offsets. Language tags are checked with the browser's `Intl.getCanonicalLocales`, which implements [RFC 5646](https://www.rfc-editor.org/rfc/rfc5646) (BCP 47). URIs must be absolute in the sense of [RFC 3986 section 4.3](https://www.rfc-editor.org/rfc/rfc3986#section-4.3) and parse with the WHATWG URL parser. ## Finding reference ### The response | Finding | Severity | Section | What it means | Fix | | --- | --- | --- | --- | --- | | Not served | Error | [3](https://www.rfc-editor.org/rfc/rfc9116#section-3) | No file where readers look | Publish one at `/.well-known/security.txt` | | Wrong media type | Error | [3](https://www.rfc-editor.org/rfc/rfc9116#section-3) | Strict readers refuse it; HTML means the app answers every path | Serve `text/plain; charset=utf-8` | | Not UTF-8 | Error | [4](https://www.rfc-editor.org/rfc/rfc9116#section-4) | Garbled characters | Save as UTF-8 | | Larger than 64 KiB | Error | Tool limit | Not a security.txt | Replace what is served | ### Fields and lines | Finding | Severity | Section | What it means | Fix | | --- | --- | --- | --- | --- | | No way to report | Error | [2.5.3](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.3) | Nowhere to send a report | Add a Contact | | No Expires date / appears more than once | Error | [2.5.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.5) | Readers may ignore the file | Keep one Expires | | Expires is not a date | Error | [2.5.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.5) | No expiry can be read | Use RFC 3339 | | The file has expired | Error | [2.5.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.5) | Contacts treated as stale | Review, re-date | | Expires more than a year ahead | Warning | [2.5.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.5) | Valid, reviewed too rarely | Date it within a year | | A web address uses http:// | Error | [2.5.3](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.3) | Can be read or replaced in transit | Use `https://` | | Not an absolute URI | Error | [4](https://www.rfc-editor.org/rfc/rfc9116#section-4) | Readers cannot follow it | Add the scheme | | Not a field line | Error | [4](https://www.rfc-editor.org/rfc/rfc9116#section-4) | Line skipped | `Name: value` or `#` | | Preferred-Languages repeated | Error | [2.5.8](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.8) | Readers take one line | One comma list | | Not a language tag | Error | [2.5.8](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.8) | Languages unclear | BCP 47 tags | | Canonical points elsewhere | Error | [2.5.2](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.2) | Copy cannot be told current | Name the served URL | | Last line has no line break | Error | [2.2](https://www.rfc-editor.org/rfc/rfc9116#section-2.2) | Last field may be dropped | End with a newline | ### Signatures | Finding | Severity | Section | What it means | Fix | | --- | --- | --- | --- | --- | | Broken signature block | Error | [RFC 9580 section 7](https://www.rfc-editor.org/rfc/rfc9580#section-7) | Fields unreliable | Re-sign or publish unsigned | | Signed, not verified here | Warning | [2.3](https://www.rfc-editor.org/rfc/rfc9116#section-2.3) | Signature not checked | Verify with `gpg --verify` | ## Guide ### No file, or a web page instead of a file 1. Fill in the draft form: Contact is required, Expires is filled with a date 364 days ahead, Canonical is set to the requested address. 2. Download the file and publish it at `/.well-known/security.txt`. 3. On a single-page app, add a static route for that path before the catch-all, and map it to `text/plain; charset=utf-8`. Confirm outside Tamperbox: ```sh curl -sSI https://example.com/.well-known/security.txt curl -sS https://example.com/.well-known/security.txt ``` The first must show `HTTP/2 200` (or `HTTP/1.1 200`) and `content-type: text/plain; charset=utf-8`. ### Expired, missing or distant Expires Review every Contact and Policy first, then set one Expires less than a year ahead, for example with `date -u -d '+364 days' +%Y-%m-%dT00:00:00Z` on GNU systems. Put the next review in the same calendar as certificate and domain renewals. ### Canonical mismatch Usually `www` against the bare domain, or a file copied from another site. List every address the file is served at, one Canonical each, or point the only Canonical at the address the redirects end on. Heal it writes the fetched URL. ### Signed files Edit the plain text, then sign it again with `gpg --clearsign security.txt` and publish the `.asc` output as `security.txt`. Every repair here removes the signature, because the signed text changes. ### Break it cases | Case | What it loads | Finding | | --- | --- | --- | | Expired yesterday | Your file with Expires set to yesterday | The file has expired | | No Contact | Your file without Contact lines | No way to report | | Expires twice | A second Expires line | Expires appears more than once | | Contact over http | A web field switched to `http://` | A web address uses http:// | | No space after a colon | `Name:value` on one line | Not a field line | | Served as a web page | A sample host answering with HTML | No security.txt | | No security.txt | A sample host answering 404 | Not served | The first five build on your own file when you checked one; the last two use reserved `harbor-supply.example` hosts answered locally. ## Worked example The page opens on `google.com`, checked live, because among the candidates compared it shows the most of the tool: a redirect, several fields and one instructive warning. The file belongs to Google and can change at any time, so read the result on the page rather than the details here, which describe the file as it was when this page was written. ### What the opening check shows The request to `https://google.com/.well-known/security.txt` is redirected once to the `www` host, and the file found there is read field by field: | Part | What the page shows | Finding | | --- | --- | --- | | Redirect | "after 1 redirect" in the verdict's detail line | None: the redirect stays on `https://` | | Contact | A web form first, then a `mailto:` address, in order of preference | None | | Encryption, Policy, Acknowledgments, Hiring | Listed under Encrypt with, Read first, Thanks and Hiring | None | | Canonical | "Not set" | None: Canonical is optional | | Expires | A date several years ahead on the time axis, past the one-year mark | Expires more than a year ahead (warning) | ### Reading it The verdict is "Valid security.txt." with a warning chip, because the only finding is a recommendation, not an error. Heal it offers "Set Expires to" a date 364 days after the check, and the corrected file appears under the listing. Take it further offers the certificate of the host serving the key, the security headers of the report page, mixed content on the policy page and the certificate of the host the redirect ended on. ### Other states `tamperbox.dev` and `gmail.com` publish no file; checking either shows "No security.txt." and the draft form, with Expires and Canonical filled in. The Break it cases show every error on a copy of the file you checked. ## For agents The Tamperbox MCP server exposes `search` and `execute`. Call `POST /v1/tools/security_txt_checker` with `{ "domain": "example.com" }` through `tamperbox.request` to fetch and check a live file; the result carries `status`, `report` (`fields`, `contacts`, `expires`, `signature`, `findings`, `valid`), `redirects` and `truncated`. For a file you already have, `POST /v1/tools/security_txt_analyze` parses it without any network request and can apply named repairs. Apply [Method](#method) to read the findings, and keep these warnings with any conclusion: - `valid: true` is syntax and rules, not evidence that the Contact is monitored. - `signature: "unverified"` means a signature was found, not that it is genuine. - A Contact URL is never fetched; the check does not test any vulnerability. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern. ## Limits - One request from one server location at one moment, to `/.well-known/security.txt` only; the legacy `/security.txt` is not requested. - OpenPGP signatures are separated but not verified. - A valid file does not show who controls the contacts, that anyone reads them, or that testing is permitted; read the Policy. - A pasted file has no status, media type, redirects or fetch URL, so those rules and the Canonical comparison need a live check. - CSAF and other extension fields are listed but not validated. - History is a browser interaction record, not server monitoring. Explicit tool links use temporary browser storage as described in [Browser transfers](#browser-transfers). ## References - [RFC 9116, A File Format to Aid in Security Vulnerability Disclosure](https://www.rfc-editor.org/rfc/rfc9116). Informational, April 2022, with no updating RFC. Its [errata](https://www.rfc-editor.org/errata/rfc9116), checked 22 October 2026: one verified editorial erratum (6946) corrects a cross-reference in the section 4 ABNF comment from section 3.5.3 to 2.5.3, and changes no rule; two reported, unverified technical errata propose that the section 2.5.5 example use an upper-case `Z` (7264) and that the ABNF `CRLF` allow a bare LF to match section 2.2 (7743). The tool already reads a lower-case `z` as valid, as RFC 3339 permits, and accepts LF or CRLF line endings, so neither proposal changes a result. Sections used: [2](https://www.rfc-editor.org/rfc/rfc9116#section-2), [2.1](https://www.rfc-editor.org/rfc/rfc9116#section-2.1), [2.2](https://www.rfc-editor.org/rfc/rfc9116#section-2.2), [2.3](https://www.rfc-editor.org/rfc/rfc9116#section-2.3), [2.4](https://www.rfc-editor.org/rfc/rfc9116#section-2.4), [2.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5), [2.5.2](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.2), [2.5.3](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.3), [2.5.5](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.5), [2.5.8](https://www.rfc-editor.org/rfc/rfc9116#section-2.5.8), [3](https://www.rfc-editor.org/rfc/rfc9116#section-3) and [4](https://www.rfc-editor.org/rfc/rfc9116#section-4). - [RFC 3339, Date and Time on the Internet: Timestamps](https://www.rfc-editor.org/rfc/rfc3339). Proposed Standard, July 2002; updated by [RFC 9557](https://www.rfc-editor.org/rfc/rfc9557). Section used: [5.6](https://www.rfc-editor.org/rfc/rfc3339#section-5.6). - [RFC 5646, Tags for Identifying Languages](https://www.rfc-editor.org/rfc/rfc5646). Best Current Practice, BCP 47, September 2009. - [RFC 3986, Uniform Resource Identifier: Generic Syntax](https://www.rfc-editor.org/rfc/rfc3986). Internet Standard, STD 66, January 2005. Section used: [4.3](https://www.rfc-editor.org/rfc/rfc3986#section-4.3). - [RFC 9580, OpenPGP](https://www.rfc-editor.org/rfc/rfc9580). Proposed Standard, July 2024; obsoletes [RFC 4880](https://www.rfc-editor.org/rfc/rfc4880). Section used: [7](https://www.rfc-editor.org/rfc/rfc9580#section-7), the cleartext signature framework. - [IANA security.txt Fields registry](https://www.iana.org/assignments/security-txt-fields). The registered field names, including CSAF. --- # SOA Lookup How the SOA Lookup reads a zone's Start of Authority record field by field, decodes a date-shaped serial, checks the refresh, retry, expire and negative-caching timers against common ranges, and how to fix and confirm each one. Canonical: https://docs.tamperbox.dev/tools/soa-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A zone or a name inside it, or an SOA record to paste Outputs: A verdict naming the zone, its primary and serial, findings for the timers and the serial, the seven fields explained, and the answer as dig-style text Limitations: One resolver's answer at one moment, not every nameserver's serial; the timer ranges are common practice, not protocol limits, and many hosted providers do not use refresh, retry or expire The tool page is [tamperbox.dev/soa-lookup](https://tamperbox.dev/soa-lookup). It opens on `harbor-supply.example`, a sample zone on the reserved `.example` zone with a date-shaped serial and timers in the usual ranges. This page is the long version: what each field of the SOA means, which timers matter to whom, the ranges the tool checks, and how to read a serial. <div class="tb-callout"><strong>Where processing happens:</strong> a name is sent to the Tamperbox server, which asks Cloudflare for its SOA record over DNS over HTTPS. A pasted SOA is read in your browser and never uploaded. Sample names under <code>.example</code> are answered in the browser. Ordinary lookup results are not persisted by this page. An explicit handoff temporarily stores its value in session storage for one-use transfer.</div> ## What the tool answers Every zone has exactly one SOA record, at its apex. It names the zone's primary nameserver and contact, carries a version number for the zone's contents, and sets four timers ([RFC 1035 section 3.3.13](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.13)). The tool answers: 1. **Which zone holds this name?** For a name inside a zone, the SOA comes back in the authority section and names the zone. 2. **Who runs it?** The primary nameserver (MNAME) and the contact mailbox (RNAME). 3. **When did it last change?** The serial, read as a date when it has the YYYYMMDDnn shape. 4. **Are the timers sensible?** Refresh, retry and expire, which steer secondary nameservers, and the negative TTL, which reaches every visitor. It does not ask each nameserver for its serial, so it cannot tell you whether every server has the latest copy; the [DNS Propagation Checker](https://tamperbox.dev/dns-propagation) with type NS, or `dig` against each server, does that. ## Inputs ### A name `example.com`, or any name inside it. The lookup runs when you stop typing, or on Enter. A pasted address or email address is reduced to its host or domain. ### A pasted SOA Anything with a space is read as records, in the browser: a dig answer, a zone file line, or the bare seven fields. A record with fewer than seven fields, or a serial or timer that is negative or non-finite, is refused with the reason ("An SOA record has seven fields…", "Serial and timers must be whole numbers of seconds."). Parentheses from multi-line zone file records are ignored. Despite the diagnostic saying “whole numbers,” the current parser accepts non-negative fractional values and does not enforce the unsigned 32-bit range. Treat this as an inspection tool, not a zone-file validator. ### Files Drop a `.txt` file anywhere on the page. ## Reading the result ### Verdict and chips "Zone example.com: primary ns1.example.net, serial 2026101301." when the timers pass, or the first timer problem otherwise, for example "Refresh is short: 5 minutes". The line under it says when the zone last changed, or that the serial is a counter, or that the name is inside the zone shown. The chip counts the timer checks that pass. ### Where your input goes A pasted SOA stays in the browser; a name means one SOA query from our server. ### Findings The timer and serial findings; passes fold into one line. ### SOA records The seven fields, each with its value and its meaning in words: primary nameserver, contact (with the first dot read as the @), serial, refresh, retry, expire, negative TTL. ### DNS response The answer as dig-style text, with a copy button. ### History and Heal it History logs every Break it and Heal it change. For a pasted SOA with a timer out of range, Heal it rewrites the out-of-range timers to common values (refresh 2 hours, retry 15 minutes, expire 2 weeks, negative TTL 1 hour) and keeps the rest. ### Take it further The serial's date as a Unix timestamp (a new tab of the timestamp tool), the primary nameserver to the DNS Lookup for its addresses, the contact's domain to the email domain check, and the zone to the DNSSEC Checker. ## Method ### 1. Finding the SOA The server asks Cloudflare for the SOA at the name. At an apex the answer holds it. For a name inside a zone, the answer is empty and the zone's SOA comes back in the authority section, as [RFC 2308 section 3](https://www.rfc-editor.org/rfc/rfc2308#section-3) requires: "Name servers authoritative for a zone MUST include the SOA record of the zone in the authority section of the response when reporting an NXDOMAIN or indicating that no data of the requested type exists." The page uses that record and says the name is inside its zone. ### 2. The fields | Field | Meaning ([RFC 1035 section 3.3.13](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.13)) | How the page shows it | | --- | --- | --- | | MNAME | "the name server that was the original or primary source of data for this zone" | Primary nameserver | | RNAME | "the mailbox of the person responsible for this zone" | Contact: the first unescaped dot becomes the @; `\.` stays a dot | | SERIAL | "The unsigned 32 bit version number of the original copy of the zone" | The number, and its date when it has the YYYYMMDDnn shape | | REFRESH | the interval before secondaries check for a new serial | Seconds, and in words | | RETRY | the interval before a failed refresh is retried | Seconds, and in words | | EXPIRE | how long secondaries keep answering without reaching the primary | Seconds, and in words | | MINIMUM | today, the TTL of negative answers | "Negative TTL", seconds and words | The MINIMUM field changed meaning. [RFC 2308 section 4](https://www.rfc-editor.org/rfc/rfc2308#section-4) deprecated its original sense and made it the negative-caching TTL; [section 5](https://www.rfc-editor.org/rfc/rfc2308#section-5) sets the lifetime of a cached negative answer to "the minimum of the SOA.MINIMUM field and SOA's TTL". ### 3. The serial A serial is read as a date only when it has ten digits, YYYYMMDDnn, with a month from 01 to 12 and a day from 01 to 31: "Changed on 2026-10-13, change 1 of that day." That is a convention ([RFC 1912 section 2.2](https://www.rfc-editor.org/rfc/rfc1912#section-2.2) recommends it), not a rule. Any serial that is not date-shaped and below one billion gives an info finding, "Serial is a counter": the number only says the zone changed, not when. Large counters such as Unix-time serials, common at hosted providers, give no finding. Serials are compared by secondaries with sequence-space arithmetic ([RFC 1982](https://www.rfc-editor.org/rfc/rfc1982#section-3)), so ordinary numeric comparison is insufficient around wraparound; this page does not compare two zone versions. ### 4. The timer ranges Each timer is compared with a range; below it the finding is "Name is short: duration", above it "Name is long: duration", both checks; inside it a pass, "Name: duration". | Timer | Range checked | Why | Source | | --- | --- | --- | --- | | Refresh | 20 minutes to 1 day | Shorter adds load for no benefit; longer leaves secondaries stale | [RFC 1912 2.2](https://www.rfc-editor.org/rfc/rfc1912#section-2.2) suggests 20 minutes to 12 hours, longer with NOTIFY | | Retry | 2 minutes to 2 hours, and shorter than refresh | A failed refresh should be retried sooner than the next regular check | RFC 1912 2.2: "typically some fraction of the refresh interval" | | Expire | 1 to 4 weeks | Longer than a plausible outage, so secondaries do not stop serving | RFC 1912 2.2: "2-4 weeks are suggested values" | | Negative TTL | 5 minutes to 1 day | How long a "does not exist" is remembered | [RFC 2308 section 5](https://www.rfc-editor.org/rfc/rfc2308#section-5) | A retry that is not shorter than refresh adds a separate check, "Retry is not shorter than refresh". The ranges are common practice, not limits in any protocol; the tool accepts one week of expire where RFC 1912 suggests two, because many providers publish one week. ### 5. Verdict The first timer check names the verdict; otherwise the zone, its primary and its serial, as a pass. ## Standards and conformance | Specification | Sections used | How the tool applies it | Where it stops | | --- | --- | --- | --- | | [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035) | [3.3.13](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.13) | All seven fields are parsed and explained | Values are not checked against the zone's own NS set | | [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308) | [3](https://www.rfc-editor.org/rfc/rfc2308#section-3), [4](https://www.rfc-editor.org/rfc/rfc2308#section-4), [5](https://www.rfc-editor.org/rfc/rfc2308#section-5) | MINIMUM is shown as the negative TTL; the authority SOA is used below the apex | The lower of MINIMUM and the record's TTL is explained, not computed | | [RFC 1912](https://www.rfc-editor.org/rfc/rfc1912) | [2.2](https://www.rfc-editor.org/rfc/rfc1912#section-2.2) | Basis for the timer ranges and the date-shaped serial | Informational; the tool's ranges are slightly wider | | [RFC 1982](https://www.rfc-editor.org/rfc/rfc1982) | [3](https://www.rfc-editor.org/rfc/rfc1982#section-3) | Explains why a serial must only grow | Serials are not compared across servers | ## Finding reference | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | Refresh / Retry / Expire / Negative caching: duration | pass | [RFC 1912 2.2](https://www.rfc-editor.org/rfc/rfc1912#section-2.2) | The timer is in the usual range | None | | Refresh is short / long | check | RFC 1912 2.2 | Secondaries check too often, or fall behind | Set 20 minutes to 1 day | | Retry is short / long | check | RFC 1912 2.2 | Failed refreshes are retried too often, or too late | Set 2 minutes to 2 hours | | Retry is not shorter than refresh | check | RFC 1912 2.2 | A failing secondary waits as long as a healthy one | Set retry to a fraction of refresh | | Expire is short / long | check | RFC 1912 2.2 | Secondaries stop serving during an outage, or serve stale data for months | Set 1 to 4 weeks | | Negative caching is short / long | check | [RFC 2308 5](https://www.rfc-editor.org/rfc/rfc2308#section-5) | Resolvers re-ask for missing names constantly, or new names stay invisible for a day or more | Set 5 minutes to 1 hour | | Serial is a counter | info | [RFC 1912 2.2](https://www.rfc-editor.org/rfc/rfc1912#section-2.2) | The serial does not say when the zone changed | None, or use YYYYMMDDnn | | No SOA record at name | info | [RFC 2308 3](https://www.rfc-editor.org/rfc/rfc2308#section-3) | No SOA came back, even in the authority section | Look up the zone apex | | The name does not exist | fail | [RFC 2308 2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1) | No zone or name here | Check the name | | The resolver could not answer | fail | [RFC 1035 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) | Validating resolvers return nothing | Check the DNSSEC chain | ## Guide ### A new name takes hours to appear Someone (often a monitoring check or the person creating the record) asked for the name before it existed, and resolvers cached the "does not exist" for the negative TTL. Lower the negative TTL to five minutes to an hour if your provider lets you, then create names before anyone asks for them. `dig example.com SOA` shows the last field. ### Secondaries serve old data Raise the serial with every change if you edit the zone by hand; secondaries copy the zone only when the serial grows. Then compare each server: `dig +short @ns1.example.net example.com SOA` and the same against every other nameserver should show the same serial. A server stuck on an old serial for longer than the refresh interval is not receiving NOTIFY or cannot transfer the zone. ### Your provider will not let you change the timers Many hosted providers manage the SOA themselves and replicate without zone transfers, so refresh, retry and expire have no effect. Then the timers are the provider's setting and nothing needs to change; the negative TTL still matters to visitors. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | A subdomain | `mail.harbor-supply.example` | The zone's SOA, from the authority section | | Timers out of range | your SOA with refresh 5 minutes, retry 10 minutes, expire 1 day, negative TTL 1 week | Every timer check, and Heal it rewriting them | | Not an SOA | your SOA cut to three fields | The refusal with its reason | | Name does not exist | `nohost.` in front of your name | NXDOMAIN | ## Worked example `harbor-supply.example` names `ivy.ns.cloudflare.com` as its primary and `hostmaster@harbor-supply.example` as its contact; the serial `2026101301` reads as "Changed on 2026-10-13, change 1 of that day". Refresh is 10000 seconds (2 hours 46 minutes), retry 2400 seconds (40 minutes), expire 604800 seconds (7 days) and the negative TTL 1800 seconds (30 minutes): all four inside their ranges, folded into one passing line. The verdict reads "Zone harbor-supply.example: primary ivy.ns.cloudflare.com, serial 2026101301." These are the values Cloudflare publishes for its zones, used here on a reserved sample name. Take it further turns the serial's date into a Unix timestamp, hands `harbor-supply.example` (the contact's domain) to the email domain check, and the zone to the DNSSEC Checker. ## For agents The Tamperbox MCP server exposes `soa_lookup` with a `name`, returning an `evidence` object with the question, status, flags, answer and authority, plus `records` for the requested type. Keep these warnings with any conclusion: - Timer assessments are operational guidance, not proof of zone correctness. - One resolver's answer; individual nameservers can hold different serials while a change spreads. - A date-shaped serial is a convention, not a guarantee of the change date. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/). The operation adds parsed SOA fields and timer checks for records in the answer. Unlike the page, it does not substitute an authority-section SOA when the answer has none. ## Limits - One answer from one resolver at one moment; nameservers are not compared. - The ranges are common practice; hosted providers may ignore refresh, retry and expire. - A pasted SOA is read as text. - Sample names under `.example` are answered in the browser. ## References - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035): section 3.3.13, SOA RDATA; section 4.1.1, response codes. - [RFC 1912](https://www.rfc-editor.org/rfc/rfc1912): common DNS operational and configuration errors. Section 2.2, SOA records. Informational. - [RFC 1982](https://www.rfc-editor.org/rfc/rfc1982): serial number arithmetic. Section 3. Updates [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034) and RFC 1035. - [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308): negative caching. Sections 2.1, 3, 4 and 5. Updates [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034) and RFC 1035. --- # SPF Checker How the checker expands an SPF record through every include and redirect, counts the DNS lookups receivers allow, grades every term, and builds a flattening plan that replaces only the includes it must. Canonical: https://docs.tamperbox.dev/tools/spf-checker/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain, or an SPF record to paste Outputs: A verdict with PASS, CHECK and FAIL chips, the lookup budget numbered in evaluation order, the include tree, the flattening plan with the flattened record, every term explained, and the findings with their fixes Limitations: The count is a bounded static expansion, not an SPF evaluation for a sender address; a, mx and exists targets are not resolved, macros are not expanded, and flattened ranges go stale when a provider changes them The tool page is [tamperbox.dev/spf-checker](https://tamperbox.dev/spf-checker). It opens on a live check of `tamperbox.dev`; replace that domain to inspect your own. This page is the long version: how the record is expanded, every rule applied to it, what each finding means for mail delivery, and how to fix and verify each one. <div class="tb-callout"><strong>Where processing happens:</strong> a domain is sent to the Tamperbox server, which asks public DNS for its TXT records and follows every include and redirect the same way, one lookup each. A pasted record is parsed in your browser; only the include and redirect names it contains are looked up. Nothing is stored.</div> ## What the tool answers SPF lets a domain publish which servers may send mail for it. Receivers read the record, follow its includes, and allow at most 10 DNS lookups while doing so. The tool answers: 1. **How many lookups does this record cost?** Every include, redirect, a, mx, ptr and exists counts, through every nested include. 2. **Is the record valid?** Every term is parsed against RFC 7208; one unknown term makes the whole record a permanent error. 3. **Which includes could be flattened, and what would the record look like?** Only includes that publish plain address ranges are candidates. 4. **What else is wrong with it?** A missing or permissive all, ptr, duplicates, void lookups, a record over 255 characters. It does not evaluate a sender address. A real receiver stops at the first matching mechanism, so mail matched early can still pass a record that is over the limit. ## Inputs ### A domain `example.com`. When you stop typing, or on Enter, the server reads the TXT records at the domain and the browser keeps the ones that start with `v=spf1`. Each include and redirect target is looked up the same way, ten levels deep at most and 100 names in total. A pasted web address or email address, such as `https://example.com/contact` or `postmaster@example.com`, is cleaned to the domain it holds, and the page says what it kept. Text with no usable domain stays as it was, and the field explains what is wrong. A domain with non-ASCII labels is converted to A-labels before it is looked up. ### An SPF record Paste the record itself, with or without the quotes DNS tools print: `v=spf1 include:_spf.example.net ~all`. It is parsed in the browser as the root of the tree, shown as "Your record". Its includes are still looked up through the server, so the count covers what a receiver would read. Two records on two lines are treated as two published records, which is itself a finding. ### Files Drop a `.txt` file anywhere on the page, or use Open file. It is read in the browser. ## Reading the result ### Verdict and chips The verdict names the outcome: the budget exceeded, the record broken, something to check, or the record checked. The line under it carries the count and, when the record is over the limit, how far the flattening plan brings it. The chips show the count against the limit, the all mechanism, whether every include was looked up, and the number of findings; each one is a button that scrolls to the section that explains it. ### Findings Everything found, worst first. Two or more passes fold into one line. A budget finding carries a "See the plan" button. The [finding reference](#finding-reference) lists them all. ### Take it further Links that carry a value derived from this result into another tool: the biggest include on its own (this page again, with that domain), the DMARC policy that uses the record, who receives mail for the domain, and the network behind the first address the record lists. Each link opens the destination with the value already in its box; nothing is put in the URL. ### History and Heal it History logs every Break it and Heal it change with what it replaced; Revert undoes the newest, Reset input returns to what you entered. Heal it offers the repairs the tool found: the flattened record, merging two records into one, changing +all to ~all, adding ~all, removing ptr, removing an invalid address mechanism, correcting a misspelt include, removing duplicates. ### Lookup budget The count against the limit, and one slot per lookup in the order a receiver makes them, each slot named by the term and the record it came from. The tenth slot is marked; anything beyond it is red. The note under the slots says how many lookups are left, or that an evaluation reaching the eleventh stops there. ### Include tree The record and every include and redirect under it, each with the record it publishes and how many lookups it costs with everything beneath it. A branch that could not be evaluated shows the reason in red. ### Flattening plan Shown only when the record is over the limit. Each top-level include is marked Flatten or Keep with the reason, the flattened record is shown split into 255-character strings with a copy button, and the note says how many characters and strings it has. ### The record, term by term Every term with its meaning and whether it costs a lookup; an unknown term is marked. ## Method Every rule below names the section of [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208) it comes from. Rules that decide a FAIL quote the normative sentence behind them. Rules marked "Tamperbox" are our own recommendations, not RFC requirements. ### Record selection The server asks public DNS for the TXT records at the name, as [section 4.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.4) prescribes ("querying for type TXT only"), and the browser keeps the answers that start with `v=spf1` followed by whitespace or the end of the record. [Section 4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) decides the outcome: "If the resultant record set includes no records, check_host() produces the "none" result. If the resultant record set includes more than one record, check_host() produces the "permerror" result." - No TXT record at the name (NXDOMAIN or an empty answer) is FAIL, "No record at domain." - TXT records, none of them SPF, is FAIL, "No SPF record at this name." - Two or more records is FAIL, "N SPF records: receivers return permerror." The first record is still parsed and expanded, so the rest of the result describes it. - A record published as several quoted strings is joined first, as [section 3.3](https://www.rfc-editor.org/rfc/rfc7208#section-3.3) requires: "the record MUST be treated as if those strings are concatenated together without adding spaces." ### Term syntax The record is split on whitespace. Each term after `v=spf1` is a mechanism from [section 4.6.1](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.1) with an optional `+`, `-`, `~` or `?` qualifier, or a `name=value` modifier. Names are compared without case, because "mechanism and modifier names are case-insensitive" (section 4.6.1). Every syntax error is FAIL, because [section 4.6](https://www.rfc-editor.org/rfc/rfc7208#section-4.6) says: "if there are any syntax errors anywhere in the record, check_host() returns immediately with the result "permerror"". | Rule | Finding | RFC section | | --- | --- | --- | | A mechanism name outside the eight in 4.6.1 | Unknown term X | [4.6.1](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.1) | | `ip4` value that is not four octets from 0 to 255 without leading zeros | Invalid IPv4 address in X | [5.6](https://www.rfc-editor.org/rfc/rfc7208#section-5.6) | | `ip6` value that does not parse as an IPv6 address | Invalid IPv6 address in X | [5.6](https://www.rfc-editor.org/rfc/rfc7208#section-5.6) | | IPv4 prefix over /32 (also reported as an invalid prefix) | Prefix too long in X | [5.6](https://www.rfc-editor.org/rfc/rfc7208#section-5.6) | | IPv6 prefix over /128, the dual `/n//n` form on `ip4` or `ip6`, a prefix on any mechanism other than `ip4`, `ip6`, `a` and `mx` | Invalid prefix in X | [5.6](https://www.rfc-editor.org/rfc/rfc7208#section-5.6) | | `include` or `exists` without a domain | include needs a domain, exists needs a domain | [5.2](https://www.rfc-editor.org/rfc/rfc7208#section-5.2), [5.7](https://www.rfc-editor.org/rfc/rfc7208#section-5.7) | | `redirect=` or `exp=` with an empty value | redirect needs a domain, exp needs a domain | [6.1](https://www.rfc-editor.org/rfc/rfc7208#section-6.1), [6.2](https://www.rfc-editor.org/rfc/rfc7208#section-6.2) | | A value attached to `all` | Invalid all mechanism X | [5.1](https://www.rfc-editor.org/rfc/rfc7208#section-5.1) | | The same modifier name twice | Duplicate X modifier | [6](https://www.rfc-editor.org/rfc/rfc7208#section-6) | ### Modifier rules The duplicate rule follows [section 6](https://www.rfc-editor.org/rfc/rfc7208#section-6): "These two modifiers MUST NOT appear in a record more than once each. If they do, then check_host() exits with a result of "permerror"." The tool applies it only to `redirect` and `exp`; repeated unknown modifiers are ignored for validity. An unknown modifier is CHECK, "Unknown modifier X". Section 6 says "Unrecognized modifiers MUST be ignored no matter where, or how often, they appear in a record", so it never breaks the record; the tool reports it because a misspelt `redirect` is silently ignored the same way (Tamperbox). ### Which terms are evaluated [Section 4.6.2](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.2): "Each mechanism is considered in turn from left to right." The tool walks the terms in that order and stops at the first `all`, following [section 5.1](https://www.rfc-editor.org/rfc/rfc7208#section-5.1): "Mechanisms listed after "all" MUST be ignored." Terms after it are not counted. `redirect` is followed only when the record has no `all`, after every mechanism, because [section 6.1](https://www.rfc-editor.org/rfc/rfc7208#section-6.1) says: "Any "redirect" modifier MUST be ignored if there is an "all" mechanism anywhere in the record." The lookup budget numbers the slots in this order, descending into each include as it is reached. ### The lookup budget [Section 4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) lists the terms that cause DNS queries: `include`, `a`, `mx`, `ptr`, `exists` and `redirect`. Each costs one; `ip4`, `ip6`, `all` and `exp` cost nothing. The rule: "SPF implementations MUST limit the total number of those terms to 10 during SPF evaluation, to avoid unreasonable load on the DNS. If this limit is exceeded, the implementation MUST return "permerror"." The count is one total for the whole tree, because [section 4.1](https://www.rfc-editor.org/rfc/rfc7208#section-4.1) says the limit "must be tracked as a single global limit for all evaluations, not just for a single instance of a recursive evaluation." An include reached twice through different branches is counted twice. | Total | Severity | Title | RFC section | | --- | --- | --- | --- | | 11 or more | FAIL | N of 10 DNS lookups | [4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) | | 9 or 10 | CHECK | N of 10 DNS lookups | none (Tamperbox early warning) | | 8 or fewer | PASS | N of 10 DNS lookups | [4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) | The total is what a receiver spends on a sender that matches nothing, since then every term is evaluated. For a sender matched earlier, "processing ends" at the match (section 4.6.2) and fewer lookups are made. ### Void lookups Section 4.6.4 also limits lookups that return nothing: "SPF implementations SHOULD limit "void lookups" to two." and "Exceeding the limit produces a "permerror" result." The tool counts a void when the TXT query for an include or redirect target returns NXDOMAIN or no TXT records at all. A target that publishes TXT records but no SPF record is not void, though it still fails (see below). More than two voids is FAIL, "N void lookups". The `a`, `mx` and `exists` queries are never made, so their voids are not counted. ### Include and redirect targets Each target is looked up as in [Record selection](#record-selection). The outcomes, and the rule behind each: | Outcome | Finding | Severity | RFC section | | --- | --- | --- | --- | | No SPF record at the target | No SPF record at the include or redirect target: permerror. | FAIL | [5.2](https://www.rfc-editor.org/rfc/rfc7208#section-5.2), [6.1](https://www.rfc-editor.org/rfc/rfc7208#section-6.1) | | Two or more SPF records | N SPF records: receivers return permerror. | FAIL | [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | | A name already being expanded higher in the same branch | Include loop | FAIL | none (Tamperbox; a loop exhausts 4.6.4) | | A name containing `%` | SPF macros need a sender IP and envelope identity | CHECK | [7](https://www.rfc-editor.org/rfc/rfc7208#section-7) | | More than ten levels, or more than 100 names | Expansion limit reached | CHECK | none (Tamperbox bound) | | SERVFAIL, timeout, truncated or inconclusive answer, or a name the server refuses | Lookup incomplete: retry before using this result. | CHECK | [4.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.4) | For an include, [section 5.2](https://www.rfc-editor.org/rfc/rfc7208#section-5.2) maps a recursive "none" to "return permerror"; for a redirect, section 6.1 says "if no SPF record is found, or if the `<target-name>` is malformed, the result is a "permerror" rather than "none"." ### How branch findings are reported A branch error appears as "domain: reason". Failing findings inside an included record (syntax errors, broken targets) are carried up to the result; CHECK findings inside it are not, and the hygiene rules below run on the top record only. An incomplete branch adds "Incomplete lookup tree" (CHECK) and every count is shown as "at least N". ### The all mechanism and record hygiene These run on the top record. [Section 4.7](https://www.rfc-editor.org/rfc/rfc7208#section-4.7) sets the default: "If none of the mechanisms match and there is no "redirect" modifier, then the check_host() returns a result of "neutral", just as if "?all" were specified as the last directive." For `ptr`, [section 5.5](https://www.rfc-editor.org/rfc/rfc7208#section-5.5): "This mechanism SHOULD NOT be published." | Finding | Severity | Rule | RFC section | | --- | --- | --- | --- | | No all mechanism | CHECK | No `all` and no `redirect` | [4.7](https://www.rfc-editor.org/rfc/rfc7208#section-4.7) | | +all allows every server on the internet | FAIL | `+all` or bare `all` | none (Tamperbox; the RFC allows it) | | ?all makes SPF neutral | CHECK | `?all` | [4.7](https://www.rfc-editor.org/rfc/rfc7208#section-4.7) | | Ends in ~all, Ends in -all | PASS | `~all` or `-all` | none (Tamperbox) | | Mechanisms after all are ignored | CHECK | A mechanism follows `all` | [5.1](https://www.rfc-editor.org/rfc/rfc7208#section-5.1) | | redirect is ignored when all is present | CHECK | Both present | [6.1](https://www.rfc-editor.org/rfc/rfc7208#section-6.1) | | ptr is deprecated | CHECK | Any `ptr` | [5.5](https://www.rfc-editor.org/rfc/rfc7208#section-5.5) | | Duplicate X | CHECK | The same term twice, compared exactly; a leading `+` is ignored | none (Tamperbox) | | N characters | INFO | Longer than one 255-character TXT string | [3.3](https://www.rfc-editor.org/rfc/rfc7208#section-3.3) | ### Flattening plan The plan is a Tamperbox method; RFC 7208 neither requires nor describes flattening, though [section 10.1.1](https://www.rfc-editor.org/rfc/rfc7208#section-10.1.1) calls a record of `ip4` terms the "Best record" for DNS cost. It appears when the total is over 10. Candidates are the top record's includes with a pass qualifier. One is flattenable only when its whole subtree holds nothing but pass-qualified `ip4` and `ip6` terms, pass-qualified nested includes and a non-pass `all`, every lookup in it succeeded, and it has no failing problems. That condition keeps the result equivalent under [section 5.2](https://www.rfc-editor.org/rfc/rfc7208#section-5.2): an include matches only when the included record returns pass, so its pass ranges are exactly what it contributes, and a `-all` inside it means "not match", not fail. Candidates are taken in order of savings (the include plus everything beneath it) until the total is 10 or lower. No plan is chosen when the top record has failures or the tree is incomplete. Each chosen include is replaced in place by its ranges, so they stay ahead of any `-` or `~` mechanism that follows. The flattened record is split into 255-character strings. If every candidate flattened still leaves it over 10, the plan says so and suggests a subdomain. An include that cannot be flattened is labelled "Keep: uses a, mx or exists" whatever the reason: it may also use `ptr`, `redirect` or a non-pass term, or have failed to resolve. A flattenable include the plan does not need is labelled "Keep: N lookups". ## Standards and conformance Where each part of the work happens: the server only asks public DNS (Cloudflare's resolver, over DNS over HTTPS) for TXT records and returns the answers. Parsing, the lookup count, the include tree, every finding and the flattening plan are computed in the browser from those answers, by static evaluation: no sender address is tested. A pasted record is parsed in the browser; names under the reserved `.example` domain are answered from synthetic data in the browser. ### RFC 7208: records and selection | Section | Requirement | What the tool does | | --- | --- | --- | | [3.1](https://www.rfc-editor.org/rfc/rfc7208#section-3.1) | SPF records are TXT records only | Queries TXT only | | [3.2](https://www.rfc-editor.org/rfc/rfc7208#section-3.2), [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | One record per name; more is permerror | FAIL, then parses the first record | | [3.3](https://www.rfc-editor.org/rfc/rfc7208#section-3.3) | Multiple strings concatenated without spaces | Joins quoted strings before parsing; the flattened record is split back into 255-character strings | | [3.4](https://www.rfc-editor.org/rfc/rfc7208#section-3.4) | Answers SHOULD fit in 512 octets (450 for the records) | Not checked | | [3.5](https://www.rfc-editor.org/rfc/rfc7208#section-3.5) | Wildcard records are discouraged | Not checked | | [4.3](https://www.rfc-editor.org/rfc/rfc7208#section-4.3) | NXDOMAIN gives "none"; IDNs MUST be A-labels | NXDOMAIN is "No SPF record"; names are converted to A-labels before lookup | | [4.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.4) | DNS errors give temperror | Marks the branch incomplete (CHECK) | | [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | Keep records starting with exactly "v=spf1" | Same; `v=spf10` is discarded | ### RFC 7208: syntax | Section | Requirement | What the tool does | | --- | --- | --- | | [4.6](https://www.rfc-editor.org/rfc/rfc7208#section-4.6) | Any syntax error is permerror | Every error is a FAIL finding; all are listed, not only the first | | [4.6.1](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.1) | Eight mechanisms, `name=value` modifiers, names case-insensitive | Implemented; terms split on any whitespace | | [5.1](https://www.rfc-editor.org/rfc/rfc7208#section-5.1) | `all` takes no value | FAIL on a value | | [5.2](https://www.rfc-editor.org/rfc/rfc7208#section-5.2), [5.7](https://www.rfc-editor.org/rfc/rfc7208#section-5.7) | `include` and `exists` need a domain-spec | FAIL when empty; the domain-spec itself is not validated | | [5.6](https://www.rfc-editor.org/rfc/rfc7208#section-5.6) | `ip4` and `ip6` networks and prefix lengths | Addresses validated; prefix ranges checked | | [6](https://www.rfc-editor.org/rfc/rfc7208#section-6) | `redirect` and `exp` at most once; unknown modifiers ignored | Duplicate redirect or exp is FAIL; repeated unknown modifiers are ignored for validity | | [7.1](https://www.rfc-editor.org/rfc/rfc7208#section-7.1) | Macro and domain-spec grammar | Not validated | ### RFC 7208: evaluation and limits | Section | Requirement | What the tool does | | --- | --- | --- | | [4.1](https://www.rfc-editor.org/rfc/rfc7208#section-4.1) | One global lookup limit across recursion | One total for the tree | | [4.6.2](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.2) | Mechanisms left to right; stop at the first match | Left to right; no match is simulated, so every term is counted | | [4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) | At most 10 DNS-querying terms | Counted statically; FAIL above 10 | | [4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) | At most 10 address records per MX or PTR record | Not checked (no address queries) | | [4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) | SHOULD limit void lookups to two | Counts TXT voids only; FAIL above two | | [4.7](https://www.rfc-editor.org/rfc/rfc7208#section-4.7) | No match and no redirect gives neutral | CHECK "No all mechanism" | | [5.1](https://www.rfc-editor.org/rfc/rfc7208#section-5.1), [6.1](https://www.rfc-editor.org/rfc/rfc7208#section-6.1) | Ignore terms after `all`; ignore `redirect` when `all` is present | Same order and exclusions | | [5.2](https://www.rfc-editor.org/rfc/rfc7208#section-5.2) | include of a domain without SPF is permerror | FAIL | | [5.5](https://www.rfc-editor.org/rfc/rfc7208#section-5.5) | `ptr` SHOULD NOT be published | CHECK | | [6.1](https://www.rfc-editor.org/rfc/rfc7208#section-6.1) | redirect to a domain without SPF is permerror | FAIL | ### RFC 7208: not evaluated The tool reads records; it does not run `check_host()` for a connection. Not covered: - the `<ip>` and `<sender>` arguments of [section 4.1](https://www.rfc-editor.org/rfc/rfc7208#section-4.1), so no pass, fail or softfail result is produced for any address - the address, MX, PTR and A queries of `a`, `mx`, `ptr` and `exists` ([sections 5.3 to 5.7](https://www.rfc-editor.org/rfc/rfc7208#section-5)), and the MX and PTR sub-limits of section 4.6.4 - macro expansion ([section 7](https://www.rfc-editor.org/rfc/rfc7208#section-7)): a branch whose name holds `%` is left unexpanded - the explanation lookup of `exp` ([section 6.2](https://www.rfc-editor.org/rfc/rfc7208#section-6.2)) - the HELO identity ([section 2.3](https://www.rfc-editor.org/rfc/rfc7208#section-2.3)), result handling ([section 8](https://www.rfc-editor.org/rfc/rfc7208#section-8)) and the Received-SPF header ([section 9](https://www.rfc-editor.org/rfc/rfc7208#section-9)) - the elapsed-time limit of section 4.6.4 (the server stops each lookup after 8 seconds instead) ### Stricter than the RFC - **The count covers every path.** Receivers stop at the first match, so mail matched early can pass a record the tool scores as over the limit. - **+all is FAIL.** RFC 7208 allows it; it makes SPF meaningless, so the tool treats it as broken. - **Includes in a record with syntax errors are still expanded and counted.** A receiver returns permerror before looking any of them up. ### More lenient than the RFC - **Separators.** Terms split on any whitespace; [section 4.6.1](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.1) allows only spaces. - **Prefix lengths with leading zeros** such as `/024` are accepted; the ABNF in section 5.6 rejects them. - **Malformed targets.** A domain-spec is not checked against section 7.1. A malformed include or redirect target is refused by the server and shown as an incomplete branch (CHECK), where receivers return permerror. - **DNS errors** are shown as incomplete (CHECK), not as the temperror of section 4.4. - **Void lookups** are counted for TXT queries only, so a record whose `a` or `mx` names do not exist may pass the void check here and fail at a receiver. - **U-labels** in a record's include or redirect target are converted to A-labels when looked up, not reported; section 4.3 says IDNs in a record "MUST be encoded as A-labels". ### Updates to RFC 7208 RFC 7208 is a Proposed Standard, updated by three documents: - [RFC 8616](https://www.rfc-editor.org/rfc/rfc8616), [section 4](https://www.rfc-editor.org/rfc/rfc8616#section-4): "All U-labels MUST be converted to A-labels before being used for an SPF validation." A domain typed with non-ASCII labels is converted to A-labels before it is looked up. Its rule on the `%{s}` and `%{l}` macros does not apply, since macros are not expanded. - [RFC 7372](https://www.rfc-editor.org/rfc/rfc7372), [section 3.2](https://www.rfc-editor.org/rfc/rfc7372#section-3.2): SMTP enhanced status codes for SPF failures. Not relevant: the tool sends no mail. - [RFC 8553](https://www.rfc-editor.org/rfc/rfc8553), [section 2.1](https://www.rfc-editor.org/rfc/rfc8553#section-2.1): registers underscored TXT names. It changes nothing the tool checks. ### RFC 9989: how SPF feeds DMARC The findings that mention DMARC follow [RFC 9989](https://www.rfc-editor.org/rfc/rfc9989), which obsoleted RFC 7489 in May 2026. The tool does not evaluate DMARC; it uses these sections to explain consequences: - [Section 4.4.2](https://www.rfc-editor.org/rfc/rfc9989#section-4.4.2): "DMARC relies solely on SPF validation of the MAIL FROM identity", and only an aligned SPF pass counts. - [Section 5.3.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.5): a message fails DMARC when no authenticated identifier aligns. A broken SPF record therefore leaves DKIM as the only path to a DMARC pass. - [Section 7.1](https://www.rfc-editor.org/rfc/rfc9989#section-7.1): `-all` can get mail rejected before DMARC runs, even mail an aligned DKIM signature would pass. This is why the guide suggests `~all` while DMARC is being rolled out. ### RFC 1035: TXT strings [RFC 1035 section 3.3](https://www.rfc-editor.org/rfc/rfc1035#section-3.3) defines a character-string as one length octet followed by at most 255 characters, and [section 3.3.14](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.14) defines TXT data as one or more of them. That is the "255-octet maximum length of a character-string" RFC 7208 section 3.3 refers to, and the basis for the INFO finding and the 255-character split of the flattened record. The tool counts characters, which equals octets for the ASCII text section 3.1 requires. ## Finding reference Each finding the checker can emit, grouped by what it judges, with what it means for mail sent as the domain and the RFC section behind it. "none" marks a Tamperbox recommendation rather than an RFC rule. ### Lookup limits The budget [RFC 7208 section 4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) sets: ten DNS-querying terms and two void lookups per evaluation. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | N of 10 DNS lookups (11 or more) | FAIL | Evaluations reaching the eleventh lookup return permerror; under DMARC that mail can fail | Remove unused includes, flatten, or move a sender to a subdomain | [4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) | | N of 10 DNS lookups (9 or 10) | CHECK | The next include breaks the record | Make room before adding a service | none | | N of 10 DNS lookups (8 or fewer) | PASS | Within the limit | | [4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) | | N void lookups | FAIL | More than two empty answers is a permanent error | Remove includes whose target has no record | [4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4) | ### Record and term syntax Problems that make the record itself unusable or ambiguous to a receiver. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | No record at domain. | FAIL | Nothing is published at the name, so SPF never passes | Publish one record | [4.3](https://www.rfc-editor.org/rfc/rfc7208#section-4.3), [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | | No SPF record at this name. | FAIL | SPF never passes; DMARC relies on DKIM alone | Publish one record | [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | | An SPF record starts with v=spf1. | FAIL | The text is not an SPF record | Start with v=spf1 | [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | | N SPF records: receivers return permerror. | FAIL | Every message fails SPF | Merge into one record | [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | | Unknown term X | FAIL | Permanent error for every receiver | Correct the term | [4.6.1](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.1) | | Invalid IPv4 address in X, Invalid IPv6 address in X | FAIL | Permanent error | Correct or remove the term | [5.6](https://www.rfc-editor.org/rfc/rfc7208#section-5.6) | | Prefix too long in X, Invalid prefix in X | FAIL | Permanent error | Use a valid prefix | [5.6](https://www.rfc-editor.org/rfc/rfc7208#section-5.6) | | include needs a domain, exists needs a domain, redirect needs a domain, exp needs a domain | FAIL | Permanent error | Add the domain | [5.2](https://www.rfc-editor.org/rfc/rfc7208#section-5.2), [5.7](https://www.rfc-editor.org/rfc/rfc7208#section-5.7), [6.1](https://www.rfc-editor.org/rfc/rfc7208#section-6.1), [6.2](https://www.rfc-editor.org/rfc/rfc7208#section-6.2) | | Invalid all mechanism X | FAIL | `all` takes no value | Remove the value | [5.1](https://www.rfc-editor.org/rfc/rfc7208#section-5.1) | | Duplicate X modifier | FAIL | Permanent error for `redirect` and `exp`; other modifiers may repeat under the RFC | Remove one | [6](https://www.rfc-editor.org/rfc/rfc7208#section-6) | | Unknown modifier X | CHECK | Receivers ignore it | Remove it | [6](https://www.rfc-editor.org/rfc/rfc7208#section-6) | ### The all mechanism and redirect How the record ends decides what happens to servers it does not list. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | No all mechanism | CHECK | Unlisted servers get neutral; SPF never fails | Add ~all or -all | [4.7](https://www.rfc-editor.org/rfc/rfc7208#section-4.7) | | +all allows every server on the internet | FAIL | Anyone passes SPF for the domain | Use ~all or -all | none | | ?all makes SPF neutral | CHECK | Unlisted servers are neither allowed nor refused | Use ~all or -all | [4.7](https://www.rfc-editor.org/rfc/rfc7208#section-4.7) | | Ends in ~all, Ends in -all | PASS | Unlisted servers soft-fail or fail | | none | | Mechanisms after all are ignored | CHECK | Those senders are not allowed | Move all to the end | [5.1](https://www.rfc-editor.org/rfc/rfc7208#section-5.1) | | redirect is ignored when all is present | CHECK | The redirect never runs | Remove one | [6.1](https://www.rfc-editor.org/rfc/rfc7208#section-6.1) | ### Costly or redundant terms Terms that work but spend lookups or bytes for nothing. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | ptr is deprecated | CHECK | Slow, unreliable, skipped by some receivers | Replace with ip4/ip6 | [5.5](https://www.rfc-editor.org/rfc/rfc7208#section-5.5) | | Duplicate X | CHECK | The copy costs a lookup | Remove one | none | | N characters | INFO | Longer than one TXT string | Publish as several quoted strings | [3.3](https://www.rfc-editor.org/rfc/rfc7208#section-3.3) | ### Include and redirect targets Findings about the records the tool follows, prefixed with the name they were found at. | Finding | Severity | What it means for mail | Fix | RFC section | | --- | --- | --- | --- | --- | | Incomplete lookup tree | CHECK | Counts are a lower bound | Retry before changing DNS | [4.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.4) | | domain: No SPF record at the include or redirect target: permerror. | FAIL | The include breaks the record | Remove the include | [5.2](https://www.rfc-editor.org/rfc/rfc7208#section-5.2), [6.1](https://www.rfc-editor.org/rfc/rfc7208#section-6.1) | | domain: N SPF records: receivers return permerror. | FAIL | The include breaks the record | Ask the provider to merge them | [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | | domain: Include loop | FAIL | The include refers back to a record above it | Break the loop | none | | domain: Expansion limit reached | CHECK | Too deep or too many names to inspect | Simplify the record | none | | domain: SPF macros need a sender IP and envelope identity | CHECK | The branch is not expanded | Nothing; evaluate with a real sender | [7](https://www.rfc-editor.org/rfc/rfc7208#section-7) | | domain: Lookup incomplete: retry before using this result. | CHECK | The branch was not read | Retry | [4.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.4) | ## Guide ### Too many DNS lookups 1. Open the include tree and find the branches that cost the most; the lookup budget numbers them in order. 2. Remove the includes of services that no longer send for you. This alone fixes most records. 3. If the record is still over 10, open the flattening plan. Heal it loads the flattened record; copy it from the Flattened record box. 4. Publish the new record as the only `v=spf1` TXT record at the domain, then check the domain again. The count should be 10 or lower. 5. Put a reminder in the calendar: flattened ranges are a snapshot. Check the flattened includes on their own page every few months, or after the provider announces a change. A sender on a subdomain with its own SPF record never counts against the main domain; that is the lasting fix for a bulk mailer. ### +all, no all, ?all End the record in `~all` while DMARC is being rolled out and in `-all` once every sender is listed. Heal it changes `+all` to `~all` and adds `~all` to a record that has none; publish the result. ### A typo or an invalid address One unknown mechanism or one bad address fails the whole record for every receiver. Heal it corrects common misspellings of `include` and removes an invalid `ip4` or `ip6` mechanism while keeping the valid ones; check the result and publish it. ### ptr Replace `ptr` with the `ip4` and `ip6` ranges of the servers it covered. Heal it removes `ptr`; add the ranges before publishing. ### Two SPF records Heal it merges them: `v=spf1` once, every term from both, and `-all` if either record had it, `~all` otherwise. Publish the merged record and delete the others. ### An include that cannot be evaluated Open the include on its own (Take it further) to see what it publishes. If the service no longer sends for you, remove the include; if it does, ask the provider to fix its record. ### Break it cases Each case is built from the record you entered or looked up, so the finding looks the way it would for you. | Case | What it does to your record | Heal it offers | | --- | --- | --- | | Two SPF records | Adds a second `v=spf1` record | Merge into one record | | +all | Replaces the all mechanism with `+all` | Change +all to ~all | | No all at the end | Removes the all mechanism | Add ~all at the end | | Invalid address | Inserts `ip4:198.51.100.300` | Remove invalid address mechanism | | ptr mechanism | Inserts `ptr` | Remove ptr | | Duplicate include | Repeats the first include | Remove 1 duplicate | | Typo in a mechanism | Misspells the first include as `inlcude:` | Fix inlcude to include | ## Worked example The page opens on a live check of `tamperbox.dev`. Its published records and findings can change over time. For the deterministic walkthrough below, enter `harbor-supply.example`. This reserved `.example` domain is answered from synthetic data in your browser; it sends no live lookup. Its record includes four mail services: ```text v=spf1 include:_spf.inboxcloud.example include:send.bulkpost.example include:mail.ticketdesk.example include:spf.officesuite.example ip4:198.51.100.24 ~all ``` The expansion costs 11 lookups: the first include nests three more, the second one more, the third uses `a` and `mx`, the fourth nests one. **SPF lookup budget exceeded: 11 of 10 DNS lookups.** The plan flattens `_spf.inboxcloud.example` (saves 4, 6 ranges) and keeps the rest: `mail.ticketdesk.example` because it uses `a` and `mx`, the other two because flattening them is not needed. The flattened record costs 7 lookups and fits in one TXT string. Heal it loads it; replace the sample with your own domain and every section, card and link is rewritten for it. ## For agents The Tamperbox MCP server runs the same checks. Search its catalog for the SPF operation, inspect the input schema, and call it with the domain or the record. Keep the warning block with any conclusion: - The count is a static expansion, not an evaluation for a sender address; mail matched by an earlier term can pass a record that is over the limit. - `a`, `mx` and `exists` targets are not resolved; macros are not expanded. - Flattened ranges are a snapshot of what a provider publishes today. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the domain travels. ## Limits - A bounded static expansion: ten levels, 100 names, no sender address, no macros, no `a`, `mx` or `exists` resolution. - Void lookups are counted only for the TXT queries the tool makes. - DNS errors and malformed target names are reported as an incomplete tree, not as the temperror or permerror a receiver would return; see [Standards and conformance](#standards-and-conformance). - Duplicate detection compares whole terms; an explicit `+` is treated as the default qualifier. - One DNS answer, from one public resolver, at one moment. - Nothing is stored. ## References - [RFC 7208, Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1](https://www.rfc-editor.org/rfc/rfc7208). Proposed Standard, updated by RFC 7372, RFC 8553 and RFC 8616. Sections used: [2.3](https://www.rfc-editor.org/rfc/rfc7208#section-2.3), [3.1](https://www.rfc-editor.org/rfc/rfc7208#section-3.1), [3.2](https://www.rfc-editor.org/rfc/rfc7208#section-3.2), [3.3](https://www.rfc-editor.org/rfc/rfc7208#section-3.3), [3.4](https://www.rfc-editor.org/rfc/rfc7208#section-3.4), [3.5](https://www.rfc-editor.org/rfc/rfc7208#section-3.5), [4.1](https://www.rfc-editor.org/rfc/rfc7208#section-4.1), [4.3](https://www.rfc-editor.org/rfc/rfc7208#section-4.3), [4.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.4), [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5), [4.6](https://www.rfc-editor.org/rfc/rfc7208#section-4.6), [4.6.1](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.1), [4.6.2](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.2), [4.6.4](https://www.rfc-editor.org/rfc/rfc7208#section-4.6.4), [4.7](https://www.rfc-editor.org/rfc/rfc7208#section-4.7), [5.1](https://www.rfc-editor.org/rfc/rfc7208#section-5.1), [5.2](https://www.rfc-editor.org/rfc/rfc7208#section-5.2), [5.5](https://www.rfc-editor.org/rfc/rfc7208#section-5.5), [5.6](https://www.rfc-editor.org/rfc/rfc7208#section-5.6), [5.7](https://www.rfc-editor.org/rfc/rfc7208#section-5.7), [6](https://www.rfc-editor.org/rfc/rfc7208#section-6), [6.1](https://www.rfc-editor.org/rfc/rfc7208#section-6.1), [6.2](https://www.rfc-editor.org/rfc/rfc7208#section-6.2), [7](https://www.rfc-editor.org/rfc/rfc7208#section-7), [7.1](https://www.rfc-editor.org/rfc/rfc7208#section-7.1), [8](https://www.rfc-editor.org/rfc/rfc7208#section-8), [9](https://www.rfc-editor.org/rfc/rfc7208#section-9), [10.1.1](https://www.rfc-editor.org/rfc/rfc7208#section-10.1.1) - [RFC 8616, Email Authentication for Internationalized Mail](https://www.rfc-editor.org/rfc/rfc8616). Proposed Standard, updates RFC 7208. Section used: [4](https://www.rfc-editor.org/rfc/rfc8616#section-4) - [RFC 7372, Email Authentication Status Codes](https://www.rfc-editor.org/rfc/rfc7372). Proposed Standard, updates RFC 7208. Section noted: [3.2](https://www.rfc-editor.org/rfc/rfc7372#section-3.2) - [RFC 8553, DNS AttrLeaf Changes](https://www.rfc-editor.org/rfc/rfc8553). Best Current Practice (BCP 222), updates RFC 7208. Section noted: [2.1](https://www.rfc-editor.org/rfc/rfc8553#section-2.1) - [RFC 9989, Domain-based Message Authentication, Reporting, and Conformance (DMARC)](https://www.rfc-editor.org/rfc/rfc9989). Standards Track, May 2026; obsoletes RFC 7489 and RFC 9091. Sections used: [4.4.2](https://www.rfc-editor.org/rfc/rfc9989#section-4.4.2), [5.3.5](https://www.rfc-editor.org/rfc/rfc9989#section-5.3.5), [7.1](https://www.rfc-editor.org/rfc/rfc9989#section-7.1) - [RFC 1035, Domain Names: Implementation and Specification](https://www.rfc-editor.org/rfc/rfc1035). Internet Standard. Sections used: [3.3](https://www.rfc-editor.org/rfc/rfc1035#section-3.3), [3.3.14](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.14) - Tamperbox guides: [Fix SPF PermError: too many DNS lookups](https://tamperbox.dev/guides/fix-spf-too-many-dns-lookups) and [DMARC rollout: from p=none to reject](https://tamperbox.dev/guides/dmarc-monitoring-to-reject) --- # SRV Lookup How the SRV Lookup reads a service's SRV records, groups targets by priority, shows each target's share of connections from its weight, recognises a service that is deliberately not offered, and how to fix and confirm each case. Canonical: https://docs.tamperbox.dev/tools/srv-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A service name such as _sip._tcp.example.com, a bare domain to pick a service for, or SRV records to paste Outputs: A verdict naming the servers and priority levels, findings, the targets drawn by priority with their shares, and the answer as dig-style text Limitations: No target is contacted, so a listed server is not proof the service runs; clients that ignore SRV connect to their own defaults; that targets are not aliases is not checked The tool page is [tamperbox.dev/srv-lookup](https://tamperbox.dev/srv-lookup). It opens on `_sip._tcp.harbor-supply.example`, a sample calling service on the reserved `.example` zone with two servers sharing the load and one backup. This page is the long version: how SRV records name a service's servers, how clients choose among them, the rules the tool applies, and how to publish a service correctly. <div class="tb-callout"><strong>Where processing happens:</strong> a service name is sent to the Tamperbox server, which asks Cloudflare for its SRV records over DNS over HTTPS. A bare domain sends nothing until you pick a service. Pasted records are read in your browser and never uploaded. Sample names under <code>.example</code> are answered in the browser. Ordinary lookup results are not persisted by this page. An explicit handoff temporarily stores its value in session storage for one-use transfer.</div> ## What the tool answers An SRV record tells a client which host and port provide a service for a domain, and in which order to try them ([RFC 2782](https://www.rfc-editor.org/rfc/rfc2782)). Mail clients use them to find IMAP and submission servers, calling apps to find SIP servers, chat servers to find each other, and games to find a server's real port. The tool answers: 1. **Which servers provide this service?** Each target host and port. 2. **Which one is tried first?** Targets grouped by priority, lowest first. 3. **How are connections shared?** Each target's share inside its priority, from its weight. 4. **Is the service deliberately off?** The "." target says so. It does not connect to the targets or check that they have addresses. ## Inputs ### A service name SRV records live at names that start with two underscore labels, the service and the protocol: `_sip._tcp.example.com`, `_imaps._tcp.example.com`, `_xmpp-server._tcp.example.com`, `_minecraft._tcp.example.com`. These names come from the IANA service name registry ([RFC 6335](https://www.rfc-editor.org/rfc/rfc6335#section-5)) and the underscored-name registry ([RFC 8552 section 2](https://www.rfc-editor.org/rfc/rfc8552#section-2)). The lookup runs when you stop typing, or on Enter. ### A bare domain `example.com` has no SRV records of its own. The page says "Pick a service" and shows eight common services in the rail: `_sip._tls`, `_sip._tcp`, `_autodiscover._tcp`, `_submission._tcp`, `_imaps._tcp`, `_caldavs._tcp`, `_xmpp-client._tcp` and `_matrix._tcp`. Clicking one looks up that service under your domain. Nothing is sent before you pick. ### Pasted records Anything with a space or a quote is read as records, in the browser: dig answers, zone file lines, or bare `priority weight port target` lines. A record that is not four fields of the right kinds is refused: "An SRV record is priority, weight, port and target, such as "10 60 5060 sip1.example.com."" Priority, weight and port must be whole numbers from 0 to 65535. ### Files Drop a `.txt` file anywhere on the page. ## Reading the result ### Verdict and chips "3 servers for SIP (calls), 2 priority levels." with the first priority's shares under it, "sip1.example.com gets 60%, sip2.example.com gets 40%." A known service is named in words; an unknown one by its name. "Not offered:" for the "." target, "Pick a service:" for a bare domain. ### Where your input goes Pasted records stay in the browser; a service name means one SRV query from our server. ### Findings Checks and notes first, then the pass naming the targets and priority levels. ### SRV records One block per priority, lowest first: "Priority 10, Tried first", then "Priority 20, Only when every priority 10 target fails". Each target shows `host:port`, a bar for its share, the share as a percentage (or "All" when it is alone in its priority) and its weight. ### DNS response The answer as dig-style text, with a copy button. ### History and Heal it History logs every Break it change, and a service picked for a bare domain; Revert and Reset input bring the input back. ### Take it further The first target and its port to the TCP Ping (connection time), to the Minecraft Server Status for a `_minecraft._tcp` record, and, for a live name, to the Open Port Checker; the first target to the DNS Lookup for its addresses. ## Method ### 1. Reading each record Each record is split into priority, weight, port and target; a trailing dot on the target is dropped. A known service is named from a catalog of 17 (SIP over TLS, SIP, Teams and Skype federation, mail client setup, mail submission with and without TLS, IMAP with and without TLS, POP3 over TLS, calendars, contacts, XMPP for clients and servers, LDAP, Kerberos, Minecraft and Matrix federation). ### 2. Rule: the "." target A set that is exactly one record with the target "." means the service is off. [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782), Target field: "A Target of "." means that the service is decidedly not available at this domain." The verdict is "Not offered", with an info finding, "Service deliberately not offered". Clients stop at once instead of trying a default server. ### 3. Priority Targets are grouped by priority, lowest first. [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782), Priority field: "A client MUST attempt to contact the target host with the lowest-numbered priority it can reach; target hosts with the same priority SHOULD be tried in an order defined by the weight field." A higher priority is used only when every target before it fails. ### 4. Weight and share Inside one priority, each target's share is its weight divided by the sum of the weights. RFC 2782, Weight field: "Larger weights SHOULD be given a proportionately higher probability of being selected." When every weight in a priority is 0, each target gets an equal share and an info finding says "Weights of 0": clients pick at random. The displayed share is a weight ratio, not a simulation of RFC 2782’s selection algorithm or a measured traffic share. In particular, mixed zero and nonzero weights are simplified; see the conformance boundary below. ### 5. Check: port 0 A real target with port 0: check, "Port 0". The port is the one the service listens on; port 0 has a meaning only beside the "." target. ### 6. Verdict "N servers for service" with the number of priority levels when there is more than one, as pass, or check when a check applies. ## Standards and conformance | Specification | Parts used | How the tool applies it | Where it stops | | --- | --- | --- | --- | | [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782) | The format of the SRV RR: Priority, Weight, Port, Target | Priorities order the tiers; weights give shares; "." means not offered; field ranges 0 to 65535 | The target "MUST NOT be an alias" and must have address records: neither is checked. With mixed weights, a weight-0 target is shown at 0%, where the RFC asks for "a very small chance". Updated by RFC 6335 and [RFC 8553](https://www.rfc-editor.org/rfc/rfc8553) | | [RFC 8552](https://www.rfc-editor.org/rfc/rfc8552) | [2](https://www.rfc-editor.org/rfc/rfc8552#section-2) | Underscored service and protocol labels are accepted in names | The registry is not consulted; unknown services are shown by name | | [RFC 6335](https://www.rfc-editor.org/rfc/rfc6335) | [5](https://www.rfc-editor.org/rfc/rfc6335#section-5) | The page offers a fixed service-name catalog | | RFC 2782 has no numbered sections; its rules sit under the field names of "The format of the SRV RR", which is how they are cited here. ## Finding reference | Finding | Severity | Source | What it means | Fix | | --- | --- | --- | --- | --- | | N targets in M priority levels | pass | [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782) | Clients know where to connect and in which order | Test each target's port | | Service deliberately not offered | info | RFC 2782, Target | Clients stop at once | Replace with a real target if you offer the service | | Port 0 | check | RFC 2782, Port | Clients cannot connect to that target | Set the service's port | | Weights of 0 | info | RFC 2782, Weight | Clients pick among the targets at random | Set weights if the servers differ in capacity | | A bare domain holds no SRV records | info | [RFC 8552 2](https://www.rfc-editor.org/rfc/rfc8552#section-2) | SRV records live under service names | Pick a service, or type the full name | | No SRV record at name | info | [RFC 2308 2.2](https://www.rfc-editor.org/rfc/rfc2308#section-2.2) | Clients fall back to their defaults or guess | Publish the record your provider lists | | The name does not exist | fail | [RFC 2308 2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1) | No service record here | Check the labels | | The resolver could not answer | fail | [RFC 1035 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) | Validating resolvers return nothing | Check the DNSSEC chain | ## Guide ### Publish a service 1. Find the exact name your software or provider expects, both labels included: `_submission._tcp`, `_imaps._tcp`, `_sip._tls`. 2. Publish one record per server: `_imaps._tcp.example.com. 3600 IN SRV 0 0 993 imap.example.com.` The target must be a host name with A or AAAA records, not a CNAME. 3. For failover, give the backup a higher priority number. For load sharing, give servers the same priority and weights in proportion to their capacity. 4. Look the name up here, then test each target: the TCP Ping link opens the first `host:port`. Confirm from a terminal: `dig +short SRV _imaps._tcp.example.com` lists `priority weight port target`, and `dig +short A imap.example.com` should return an address, not a CNAME. ### Say a service is not offered Publish `0 0 0 .` at the service name. Mail clients probing a domain then stop looking for that protocol instead of guessing hosts. ### Mail client setup (autodiscover) goes to the wrong server `_autodiscover._tcp` points mail clients at the server that hands out their settings. Look it up here; a target left over from a previous mail provider sends every new client to the old one. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | Service not offered | a sample service with the "." target | "Not offered" | | A bare domain | your domain without the service labels | "Pick a service" and the common services | | One server | a sample autodiscover record | "1 server for mail client setup" | | Bad fields | your first record with a field missing | The refusal with its reason | ## Worked example `_sip._tcp.harbor-supply.example` lists three servers. At priority 10, `sip1.harbor-supply.example` has weight 60 and `sip2.harbor-supply.example` weight 40, so the displayed weight ratios are 60% and 40%; at priority 20, `sip-backup.harbor-supply.example` is used only when both of those fail. All three listen on port 5060. The verdict reads "3 servers for SIP (calls), 2 priority levels." and Findings folds one pass, "3 targets in 2 priority levels". Take it further hands `sip1.harbor-supply.example:5060` to the TCP Ping and the host to the DNS Lookup, both of which answer the sample in the browser. Press "Service not offered" for the "." target, and "A bare domain" to see the service picker. ## For agents The Tamperbox MCP server exposes `srv_lookup` with a complete service `name` such as `_sip._tcp.example.com`; it does not offer services for a bare domain. It returns an `evidence` object containing the question, status, flags, answer and authority, plus `records` for the requested type. Keep these warnings with any conclusion: - The operation does not connect to the advertised service. - Shares follow from the weights inside a priority; clients that ignore SRV connect elsewhere. - One answer from one resolver at one moment. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/). The response also contains parsed records and priority `tiers`; these are calculated shares, not a measurement of traffic distribution. ## Limits - No target is contacted, and the targets' addresses are not looked up. - A target that is an alias is not reported, although RFC 2782 forbids it. - Pasted records are read as text. - One answer from one resolver at one moment. - Sample names under `.example` are answered in the browser. ## References - [RFC 2782](https://www.rfc-editor.org/rfc/rfc2782): a DNS RR for specifying the location of services (DNS SRV). The Priority, Weight, Port and Target fields. Updated by RFC 6335 and [RFC 8553](https://www.rfc-editor.org/rfc/rfc8553). - [RFC 8552](https://www.rfc-editor.org/rfc/rfc8552): scoped interpretation of DNS resource records through underscored naming. Section 2. - [RFC 6335](https://www.rfc-editor.org/rfc/rfc6335): IANA procedures for the service name and port number registry. Section 5. - [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308): sections 2.1 and 2.2. --- # SSL Certificate Checker What the certificate checker connects to, every rule it applies to a chain, what each finding means for the people behind the host, and how to fix and verify each one. Canonical: https://docs.tamperbox.dev/tools/ssl-checker/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: A host name the server can reach on port 443 or a mail port, or a PEM chain or openssl s_client output to paste Outputs: A verdict with PASS, CHECK and FAIL chips, the chain on one time axis, the names covered, the connection negotiated and the chain as PEM Limitations: One connection from one location at one moment; revocation (OCSP and CRL) is not checked; a pasted chain is read, not verified against any root store The tool page is [tamperbox.dev/ssl-checker](https://tamperbox.dev/ssl-checker). It opens by checking `tamperbox.dev` live, answers in one sentence, and shows the evidence under it. This page is the long version: what the probe does, every rule it applies, what each finding means, and how to fix and verify each one. <div class="tb-callout"><strong>Where processing happens:</strong> a host name is sent to the Tamperbox server, which opens one TLS connection and returns what the server sent. Pasted certificates and openssl output are read in your browser and never uploaded. Nothing is stored.</div> ## What the tool answers Four questions, in the order a browser asks them: 1. **Is the chain trusted?** Does it verify against a public root store, with the host name checked? 2. **Does it name this host?** Is the host covered by the certificate's DNS names? 3. **Is it in date, and for how long?** Not expired, not valid-yet, and not inside the last third of its lifetime, where renewal should already have happened. 4. **Is the rest sound?** The chain in order and complete, keys and signatures strong enough, a current TLS version negotiated. The verdict sentence answers the worst of these. The chips repeat the three that matter most (trust, name, expiry) and any failure beyond them. Findings under the verdict list everything, worst first. ## Inputs ### A host name `example.com` or `www.example.com`. The check runs on port 443 when you stop typing, or on Enter. A scheme or a path is ignored: `https://example.com/login` checks `example.com`. ### A host name with a mail port Add `:25`, `:465`, `:587`, `:993`, `:995` or `:853` to check a mail server or a DNS-over-TLS resolver. On 25 and 587 the probe speaks SMTP first (reads the greeting, sends EHLO, requires STARTTLS to be advertised) and then upgrades the connection. The other ports start in TLS. Any other port is refused with a note, because the probe knows how to talk only to these services. | Port | Service | How the probe connects | | --- | --- | --- | | 443 | HTTPS | TLS at once, SNI set to the host, ALPN offers h2 and http/1.1 | | 25, 587 | SMTP | Plain SMTP, EHLO, STARTTLS, then TLS | | 465 | SMTPS | TLS at once | | 993 | IMAPS | TLS at once | | 995 | POP3S | TLS at once | | 853 | DNS over TLS | TLS at once | The key exchange group, the ALPN result and the post-quantum link are reported for port 443 only. ### A pasted chain Paste one or more PEM blocks (`-----BEGIN CERTIFICATE-----` …), or the output of: ```sh openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null ``` Pasted input is read in the browser. Two reading options appear in the rail: - **Host name to match.** The host to check the certificate's names against. The page guesses it from a `-servername` or `-connect` argument in openssl output. Leave it empty to list the names without matching. - **Check dates on.** The day to judge validity on, at noon UTC. Defaults to today. Break it uses it to show "the day after it expires". If the openssl output contains a `Verify return code` line, the page shows that result as reported by whoever ran openssl, marked "Pasted verification result". It is not confirmed by the tool. Pasted chains without such a line are marked "Trust not checked". ### Files Drop a `.pem`, `.crt`, `.cer` or `.txt` file anywhere on the page, or use Open file. Files up to 128 KiB are read in the browser. ## Reading the result ### Verdict and chips The verdict names the outcome and the worst finding, then one line of facts: the host, the port, the address the probe connected to and the moment it did so. For a pasted chain the line says how many certificates were read, the date judged on and the host matched against. The chips are buttons. A CHECK or FAIL chip scrolls to the section that explains it. ### Findings Every finding, worst first: FAIL, then CHECK, then INFO. Passes fold into one line, "n checks passed", that opens on click. Each finding has a title, one sentence on what it means for whoever receives the output, and the fix where there is one. The [finding reference](#finding-reference) below lists them all. ### Certificate chain The signature section. Every certificate the server sent, in the order it sent them, on one time axis: - The bar is the certificate's validity. The vertical mark is the moment of the check. - On your certificate, the hatched last third of the bar is the renewal window: ACME clients normally renew before it starts. - The right column shows days left, or "Expired" with how long ago. - Labels under the name say what the certificate is (yours, intermediate, root), who issued it, its key and signature algorithm. "Not needed" marks a root the server sends but clients already have. "Self-signed" marks a certificate that signs itself in first position. - A missing intermediate is drawn as a dashed ghost row where it should be, marked "Not sent". - A broken link ("X, sent next, did not issue this certificate") is printed under the certificate it breaks from. ### Names it covers Every DNS name in the certificate's Subject Alternative Names, the one that covers the checked host outlined and marked "matches" (or "covers host" for a wildcard). A certificate with no DNS names shows its common name instead, and gets a finding, because browsers ignore the common name. ### Connection What this one handshake negotiated: protocol, cipher, key exchange group (with a note on whether it is post-quantum), ALPN, the address connected to, and the moment. Only the values this connection negotiated are known, not every version or cipher the server allows. ### Certificate details and Chain as PEM Every certificate's subject, issuer, serial, dates, key, signature algorithm, SHA-256 fingerprint and CA flag, each with a Copy PEM button. Under it, the whole chain as PEM, exactly as the server sent it, to copy or download. Certificates are public data: they contain no private keys. ### History Every Break it and Heal it change, newest first, with what it replaced. Revert undoes the newest change; Reset input returns to what you entered. ### Take it further A link that carries a value from this result into another security tool: the host and port to the DANE checker, for a live connection. The other security checks on the same host are in Check the rest, and the result's Key exchange row links the post-quantum checker for port 443. The link opens the other tool with the value already in its box; nothing is put in a URL. ## Method The same rules read a live chain and a pasted one. The difference is that a live chain also has a trust result from the probe, while a pasted chain is judged against the host name and date you choose. Each rule below names the section it comes from; rules marked as Tamperbox recommendations have no specification behind them. Findings come in three severities: | Severity | Shown as | Meaning | | --- | --- | --- | | Problem | FAIL | A browser or client refuses the connection or warns | | Warning | CHECK | Works today; needs attention before it stops working or is refused by strict clients | | Information | INFO | Worth knowing; nothing to change | ### Trust and the verification result On port 443 the probe resolves the host, refuses it unless every address is public, and runs `openssl s_client` against the first address. It sends the host name as SNI ([RFC 6066, Section 3](https://www.rfc-editor.org/rfc/rfc6066#section-3)), offers `h2` and `http/1.1` through ALPN ([RFC 7301, Section 3.1](https://www.rfc-editor.org/rfc/rfc7301#section-3.1)), and asks OpenSSL to verify the chain with the host name checked (`-verify_hostname`). Up to ten certificates are kept from what the server sends. OpenSSL runs the path validation of [RFC 5280, Section 6.1](https://www.rfc-editor.org/rfc/rfc5280#section-6.1) against the CA bundle installed in the probe container. Trust is PASS only when OpenSSL returns code 0. The rule follows [RFC 9846, Appendix C.2](https://www.rfc-editor.org/rfc/rfc9846#appendix-C.2): "certificates should always be verified to ensure proper signing by a trusted certificate authority (CA)." Browser trust stores and policies differ from the probe's. A chain the probe verifies can still be refused by a browser that distrusts the authority, and the reverse. #### OpenSSL result codes Verification is OpenSSL's; its result code becomes a plain-language finding: | Code | Finding | Fix offered | | --- | --- | --- | | 0 | Verified by the probe (PASS) | | | 2 | The issuer certificate is missing | Serve the full chain: your certificate followed by its intermediates | | 9 | Not valid yet | Check the server clock, or wait for the start date | | 10 | The certificate has expired | Renew the certificate and reload the server | | 18 | Self-signed certificate | Use a certificate from a public authority, such as a free ACME one | | 19 | Self-signed root in the chain is not trusted | Use a certificate from a public authority | | 20 | The chain does not reach a trusted root | Serve the full chain | | 21 | The first certificate could not be verified | Serve the full chain | | 62 | The certificate does not name this host | Add this host name to the certificate, or use the certificate issued for it | | 66 | The certificate key is too weak | Reissue with a 2048-bit RSA or a P-256 key | | 68 | A certificate in the chain uses a weak key | Reissue the chain with stronger keys | | other | The chain did not verify | Check the chain the server sends | #### Mail ports and pasted chains Mail ports go through a different client in the same probe: Node.js TLS, with Node's own bundled root list, after SMTP STARTTLS on ports 25 and 587 ([RFC 3207, Section 4](https://www.rfc-editor.org/rfc/rfc3207#section-4)). Node's error name is mapped to the codes above (for example `CERT_HAS_EXPIRED` to 10). A name mismatch on a mail port arrives as `ERR_TLS_CERT_ALTNAME_INVALID`, which has no mapping, so it shows as "The chain did not verify" next to "Does not name host". Pasted certificates are marked "Trust not checked" (INFO) unless the pasted openssl output carries a `Verify return code` line, in which case that code is reported as "Pasted verification result" (INFO) without confirmation. ### Name coverage The host is matched against the certificate's DNS Subject Alternative Names ([RFC 5280, Section 4.2.1.6](https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6)), case-insensitively, with a trailing dot ignored, as [RFC 9525, Section 6.3](https://www.rfc-editor.org/rfc/rfc9525#section-6.3) requires for labels. - A wildcard covers exactly one left-most label: `*.example.com` covers `www.example.com`, not `example.com` and not `a.b.example.com`. Section 6.3: "The wildcard character appears only as the complete content of the left-most label" and "A wildcard in a presented identifier can only match one label in a reference identifier." - The subject common name is displayed for context when there are no DNS names but is never used to match a service. Such a certificate gets its own FAIL, "No DNS names", from [Baseline Requirements 7.1.2.7.12](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#712712-subscriber-certificate-subject-alternative-name): "the Subject Alternative Name MUST be present and MUST contain at least one dNSName or iPAddress GeneralName". The tool counts DNS names only. - No match is FAIL, "Does not name host", unless the probe already reported code 62. [RFC 9525, Section 6.6](https://www.rfc-editor.org/rfc/rfc9525#section-6.6): an automated client "SHOULD terminate the communication attempt with a bad certificate error". On port 443 the match comes from Node's certificate host check and OpenSSL's code 62, not from the page's own matcher; see [where the live probe differs](#where-the-tool-differs-live-probe). Typical causes: a certificate issued for `www` served on the bare domain, a second-level subdomain under a wildcard, or a server returning its default certificate because no virtual host matched the SNI name. ### Expiry and the renewal window No fixed day count is used. The warning point depends on how long the certificate was issued for. Dates follow [RFC 5280, Section 4.1.2.5](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5): "The validity period for a certificate is the period of time from notBefore through notAfter, inclusive." Path validation step (a)(2) of [Section 6.1.3](https://www.rfc-editor.org/rfc/rfc5280#section-6.1.3) requires that "The certificate validity period includes the current time." | State | Severity | Title | Source | | --- | --- | --- | --- | | Past its end date | FAIL | Expired N days ago (or Expired today) | RFC 5280, 4.1.2.5 | | Before its start date | FAIL | Not valid yet | RFC 5280, 4.1.2.5 | | Less than a third of its lifetime left | CHECK | Renew soon: N days left | Tamperbox recommendation | | Otherwise | PASS | N days left | RFC 5280, 4.1.2.5 | For a 90-day certificate the warning starts under 30 days. ACME clients ([RFC 8555](https://www.rfc-editor.org/rfc/rfc8555)) commonly renew at about two thirds of the lifetime, so a CHECK here almost always means renewal has failed, or ran and the server never reloaded the new file. The one-third threshold is a Tamperbox choice; no specification sets it. An intermediate that ends before your certificate gets its own CHECK, "X expires first", because step (a)(2) applies to every certificate in the path: the chain breaks on the intermediate's date even though yours is still valid. The expiry FAIL is not repeated when the probe already reported code 10 (expired) or 9 (not valid yet). ### Lifetime limit The total lifetime is compared with the public TLS limit in [Baseline Requirements 6.3.2](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#632-certificate-operational-periods-and-key-pair-usage-periods), for example: "Subscriber Certificates issued on or after 2026-03-15 and before 2027-03-15 SHOULD NOT have a Validity Period greater than 199 days and MUST NOT have a Validity Period greater than 200 days." The tool uses the MUST NOT figure: | Issued on or after | Maximum lifetime | | --- | --- | | before 15 March 2026 | 398 days | | 15 March 2026 | 200 days | | 15 March 2027 | 100 days | | 15 March 2029 | 47 days | A certificate does not record when it was issued, so the start date (notBefore) stands in for the issuance date. The [subscriber certificate profile in 7.1.2.7](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#7127-subscriber-server-certificate-profile) requires notBefore to be "A value within 48 hours of the certificate signing operation", which keeps the estimate close. A longer lifetime is CHECK, "Valid for N days": public authorities no longer issue it, so the certificate is almost certainly from a private authority and trusted only where that root is installed. ### Chain order and completeness Each certificate's issuer should be the subject of the certificate after it. [RFC 9846, Section 4.5.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1): "The sender's certificate MUST come in the first CertificateEntry in the list. Each following certificate SHOULD directly certify the one immediately preceding it." The tool compares the issuer name with the next subject name; it does not check signatures. - **Out of order** (CHECK): every certificate is present but not each followed by its issuer. The same section says clients "SHOULD be prepared to handle potentially extraneous certificates and arbitrary orderings", so this is a warning, not a failure. A pasted chain can be reordered with Heal it. - **Gap** (FAIL): a link is missing altogether; "Certificate 3 did not sign certificate 2". - **Intermediate not sent**: the server sent only its own certificate, which is not self-signed. CHECK when the live chain still verified (the probe filled the gap from its store), FAIL otherwise. Not repeated when OpenSSL already reported code 2, 20 or 21. - **Root certificate sent** (INFO): the chain ends in a self-signed root. Section 4.5.1 says a trust anchor "MAY be omitted from the chain", so sending it is allowed and only adds bytes. - **Your certificate was not first** (CHECK, pasted only): the first non-CA certificate (by the cA flag of [RFC 5280, Section 4.2.1.9](https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.9)) is read as yours and the chain reordered for reading. ### Keys and signatures - An RSA key under 2048 bits anywhere below the root is FAIL. [Baseline Requirements 6.1.5](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#615-key-sizes): the CA SHALL "Ensure that the modulus size, when encoded, is at least 2048 bits". [RFC 9846, Appendix C.2](https://www.rfc-editor.org/rfc/rfc9846#appendix-C.2) says the same for clients. RSA of 2048 bits or more, ECDSA on P-256, P-384 or P-521, Ed25519 and Ed448 pass. If the probe already refused the key (codes 66 and 68) the finding is not repeated. - A SHA-1 or MD5 signature on any certificate other than the root is FAIL. [RFC 9846, Section 4.5.1.3](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.3): an endpoint that must validate an MD5-based signature "MUST abort the handshake with a "bad_certificate" alert", and doing the same for SHA-1 is RECOMMENDED. [Baseline Requirements 7.1.3.2](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#7132-signature-algorithmidentifier) has ended SHA-1 for public certificates. ### Protocol and key exchange - TLS 1.0 or 1.1 negotiated is FAIL. [RFC 8996, Section 4](https://www.rfc-editor.org/rfc/rfc8996#section-4): "TLS 1.0 MUST NOT be used." [Section 5](https://www.rfc-editor.org/rfc/rfc8996#section-5): "TLS 1.1 MUST NOT be used." TLS 1.2 and 1.3 pass, with a note that 1.3 is needed for post-quantum key exchange. - The key exchange group ([RFC 9846, Section 4.3.7](https://www.rfc-editor.org/rfc/rfc9846#section-4.3.7)) is reported for port 443. The verdict on it is a Tamperbox classification: INFO "Classical key exchange" (secure today, but recorded traffic could be decrypted by a future quantum computer), PASS for a post-quantum hybrid such as X25519MLKEM768, CHECK for an obsolete pre-standard Kyber draft, INFO for an unrecognised group. The connection table links to the post-quantum checker for the full picture. ## Standards and conformance The checker reads evidence from one TLS connection made by our server, then judges it in your browser with the rules above. A pasted chain is parsed locally, byte by byte from its DER encoding, and never leaves the browser. The tool is an observer: it reports what one handshake and one chain show, and it is not a conforming TLS client or path validator itself. Path validation is delegated to OpenSSL (port 443) or Node.js (mail ports) and is absent for pasted chains. ### RFC 9846: TLS 1.3 [RFC 9846](https://www.rfc-editor.org/rfc/rfc9846) is a Proposed Standard (July 2026). It obsoletes RFC 8446, the previous TLS 1.3 specification, and also RFC 5246 (TLS 1.2), 5077, 6961, 7627 and 8422. | Section | Requirement | What the tool does | | --- | --- | --- | | [4.3.7](https://www.rfc-editor.org/rfc/rfc9846#section-4.3.7) | Client lists the groups it supports | The probe offers OpenSSL's default list; the negotiated group is reported on port 443 only | | [4.5.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1) | Sender's certificate first; each following one SHOULD certify the one before | Checked by name only; out of order CHECK, gap FAIL | | [4.5.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1) | A trust anchor MAY be omitted | Root sent is INFO, never a fault | | [4.5.1.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.1) | OCSP status in the certificate entry | Not requested; `s_client` runs without `-status` | | [4.5.1.2](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.2) | Clients SHOULD send `server_name` | SNI is always sent, on every port | | [4.5.1.3](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.3) | Empty Certificate message MUST abort | "No certificate" FAIL | | [4.5.1.3](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.3) | MD5 MUST abort, SHA-1 RECOMMENDED to abort; trust anchors exempt | Both FAIL on any certificate not read as a root | | [Appendix C.2](https://www.rfc-editor.org/rfc/rfc9846#appendix-C.2) | Paths weaker than 2048-bit RSA or 224-bit ECDSA are not appropriate | RSA under 2048 bits FAIL; ECDSA passes only on P-256, P-384, P-521 | Because RFC 9846 obsoletes RFC 5246, TLS 1.2 is no longer described by its own current RFC; [Section 1.4](https://www.rfc-editor.org/rfc/rfc9846#section-1.4) lists the changes that affect it. The tool still reports TLS 1.2 as PASS. ### RFC 5280: certificates and path validation [RFC 5280](https://www.rfc-editor.org/rfc/rfc5280) is a Proposed Standard, updated by RFC 6818, 8398, 8399, 9549, 9598, 9608, 9618, 9925 and 10007. None of the updates changes the fields the tool reads. | Section | Requirement | What the tool does | | --- | --- | --- | | [4.1.2.5](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5) | Validity is notBefore through notAfter, inclusive | Expired only after notAfter, not valid yet only before notBefore | | [4.1.2.5.1](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5.1) | UTCTime year under 50 is 20YY, otherwise 19YY | Local parser does exactly this; GeneralizedTime read as is | | [4.2.1.6](https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6) | Identities go in the subject alternative name | DNS, IP, email and URI entries read; only DNS names shown and matched | | [4.2.1.9](https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.9) | The cA boolean marks a CA | Read locally; finds your certificate in a pasted chain | | [6.1](https://www.rfc-editor.org/rfc/rfc5280#section-6.1), [6.1.3](https://www.rfc-editor.org/rfc/rfc5280#section-6.1.3) | Verify signature, validity, revocation and issuer name for each certificate | Port 443: OpenSSL; mail ports: Node.js; pasted: not done. Revocation, step (a)(3), never | | [7.1](https://www.rfc-editor.org/rfc/rfc5280#section-7.1) | Name comparison rules for distinguished names | Not applied locally: issuer and subject are compared as exact strings | ### RFC 9525: service identity [RFC 9525](https://www.rfc-editor.org/rfc/rfc9525) is a Proposed Standard (November 2023) that obsoletes RFC 6125, which older implementations may still follow. | Section | Requirement | What the tool does | | --- | --- | --- | | [2](https://www.rfc-editor.org/rfc/rfc9525#section-2) | "The Common Name RDN MUST NOT be used to identify a service" | Common-name fallback disabled; SAN DNS names required | | [4.1](https://www.rfc-editor.org/rfc/rfc9525#section-4.1) | Certificate SHOULD include a DNS-ID | No DNS names is FAIL, stricter than the SHOULD (it follows the Baseline Requirements) | | [6.3](https://www.rfc-editor.org/rfc/rfc9525#section-6.3) | Case-insensitive label match; wildcard only as the whole left-most label, matching one label | Local matcher does this, and also refuses a wildcard over a single remaining label such as `*.com` | | [6.3](https://www.rfc-editor.org/rfc/rfc9525#section-6.3) | Convert U-labels to A-labels before comparing | Not done for Host name to match; a Unicode host never matches | | [6.6](https://www.rfc-editor.org/rfc/rfc9525#section-6.6) | No match: terminate with a bad certificate error | FAIL | ### RFC 8996: TLS 1.0 and 1.1 [RFC 8996](https://www.rfc-editor.org/rfc/rfc8996) is a Best Current Practice (BCP 195). The tool applies [Section 4](https://www.rfc-editor.org/rfc/rfc8996#section-4) and [Section 5](https://www.rfc-editor.org/rfc/rfc8996#section-5) as a protocol FAIL. In practice the FAIL appears for pasted transcripts only. The probe's clients (OpenSSL 3 for port 443 and Node.js 22, whose default minimum is TLS 1.2, for mail ports) do not offer TLS 1.0 or 1.1. A server that accepts nothing newer makes the live handshake fail, and the page shows an error instead of a finding. ### SNI, ALPN and SMTP STARTTLS | Specification | Section | What the tool does | | --- | --- | --- | | [RFC 6066](https://www.rfc-editor.org/rfc/rfc6066), Proposed Standard, updated by RFC 9846 | [3](https://www.rfc-editor.org/rfc/rfc6066#section-3), Server Name Indication | Host name sent as SNI on every port | | [RFC 7301](https://www.rfc-editor.org/rfc/rfc7301), Proposed Standard | [3.1](https://www.rfc-editor.org/rfc/rfc7301#section-3.1), the ALPN extension | Port 443 offers `h2,http/1.1`; the result is shown, not judged; mail ports offer none | | [RFC 3207](https://www.rfc-editor.org/rfc/rfc3207), Proposed Standard | [4](https://www.rfc-editor.org/rfc/rfc3207#section-4), the STARTTLS command | Ports 25 and 587: greeting, EHLO, STARTTLS must be advertised, 220 reply, then TLS | Ports 465, 993, 995 and 853 start in TLS at once. ### CA/Browser Forum Baseline Requirements The [TLS Baseline Requirements](https://cabforum.org/working-groups/server/baseline-requirements/requirements/) are not an IETF standard but bind publicly trusted authorities. The tool was checked against version 2.3.1, dated 4 October 2026. | Section | Requirement | What the tool does | | --- | --- | --- | | [6.1.5](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#615-key-sizes) | RSA at least 2048 bits; ECDSA on P-256, P-384 or P-521; "No other algorithms or key sizes are permitted." | RSA and ECDSA rules match; Ed25519 and Ed448 still PASS | | [6.3.2](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#632-certificate-operational-periods-and-key-pair-usage-periods) | Maximum validity by issuance date | Lifetime CHECK above the MUST NOT limit, by notBefore | | [7.1.2.7](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#7127-subscriber-server-certificate-profile) | notBefore within 48 hours of signing | Justifies notBefore as the issuance estimate | | [7.1.2.7.12](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#712712-subscriber-certificate-subject-alternative-name) | SAN present with a dNSName or iPAddress | "No DNS names" FAIL; IP entries do not count | | [7.1.3.2](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#7132-signature-algorithmidentifier) | SHA-1 sunset | SHA-1 FAIL below the root | The requirements apply to public authorities only. The tool applies them to every certificate and says so in the lifetime finding. ### What the tool does not check - **Revocation.** Neither OCSP nor CRLs are consulted, and no stapled OCSP response is requested ([RFC 9846, Section 4.5.1.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.1); [RFC 5280, Section 6.1.3](https://www.rfc-editor.org/rfc/rfc5280#section-6.1.3) step (a)(3)). A revoked certificate can pass. - **Certificate Transparency.** Embedded signed certificate timestamps are not read. Browsers that enforce a CT policy can refuse a certificate the tool passes. CT is specified in [RFC 6962](https://www.rfc-editor.org/rfc/rfc6962), obsoleted by [RFC 9162](https://www.rfc-editor.org/rfc/rfc9162); both are Experimental. - **Signatures in a pasted chain.** Links are checked by name; no signature is verified, so a forged chain with matching names reads as complete. - **Extensions beyond names and the cA flag.** The page does not read key usage, extended key usage, name constraints or policies. - **Everything the server allows.** Only the version, cipher and group this one handshake negotiated are known. - **Browser trust.** Trust is the probe's root store, not a browser's, and browser distrust decisions are not modelled. ### Where the tool differs: live probe - **Two root stores.** Port 443 is verified by the OpenSSL command line against the container's CA bundle; mail ports by Node.js against its bundled root list. A chain can verify on one and not the other. - **Strict SAN matching across transports.** Partial wildcards such as `w*.example.com` are rejected under [RFC 9525 section 6.3](https://www.rfc-editor.org/rfc/rfc9525#section-6.3). Common-name fallback is disabled. A mail-probe hostname mismatch maps to the shared name error and is shown once. - **Mail port chains are rebuilt.** Node returns the verified path, not the list the server sent, and the path can include a root from Node's store. A mail server that sends only its own certificate can then show two certificates, a "Root certificate sent" INFO, and no "Intermediate not sent" finding. Order findings on mail ports describe that path. ### Where the tool differs: local reading - **Common name fallback.** RFC 9525 forbids it; the tool uses it when there are no DNS names, so "Names host" can PASS next to the "No DNS names" FAIL. The verdict is still FAIL. - **Lifetime counted one second short.** The tool divides notAfter minus notBefore by 86,400 seconds and rounds up. RFC 5280 and the Baseline Requirements count the period inclusively, so a certificate whose dates are exactly 398 days apart lasts 398 days and one second, which the requirements count as 399 days. The tool sees 398 and does not warn. - **Self-signed by name.** A certificate whose subject equals its issuer is read as self-signed. RFC 5280 calls that self-issued; self-signed also needs the signature to verify with its own key, which is not checked. - **SHA-1 on a self-signed leaf.** Section 4.5.1.3 exempts self-signed certificates; the tool exempts only a root after the first position, so a self-signed SHA-1 server certificate is FAIL. - **Distinguished names compared as strings**, not with the rules of RFC 5280, Section 7.1. Names that differ only in letter case or spacing read as a gap. ## Finding reference Every finding the tool can emit, by its id, with what it means for the people who connect to the host. The Source column links the section a finding rests on. "none" marks a Tamperbox recommendation or a report of what the tool could not establish, not a rule from a specification. BR means the CA/Browser Forum TLS Baseline Requirements. ### Trust and names Whether clients accept the certificate for this host at all. | Id | Severity | Title | Source | What it means | Fix | | --- | --- | --- | --- | --- | --- | | trust | PASS | Verified by the probe | [RFC 5280, 6.1](https://www.rfc-editor.org/rfc/rfc5280#section-6.1) | The chain verifies against the probe's trust store | | | trust | FAIL | One of the verification titles above | [RFC 5280, 6.1.3](https://www.rfc-editor.org/rfc/rfc5280#section-6.1.3) | Browsers warn or refuse | See the table above | | trust | INFO | Trust not checked, Trust not established, or Pasted verification result | none | No trust verdict is available for a pasted chain, or the probe did not report success | Check the host name live | | name | PASS | Names host | [RFC 9525, 6.3](https://www.rfc-editor.org/rfc/rfc9525#section-6.3) | One of the certificate's names covers the host | | | name | FAIL | Does not name host | [RFC 9525, 6.6](https://www.rfc-editor.org/rfc/rfc9525#section-6.6) | Browsers warn that the connection is not private | Add the name, or serve the certificate issued for it | | san | FAIL | No DNS names | [BR 7.1.2.7.12](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#712712-subscriber-certificate-subject-alternative-name) | Browsers ignore the common name | Reissue with Subject Alternative Names | | none | FAIL | No certificate | [RFC 9846, 4.5.1.3](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.3) | The server presented none | Configure TLS on this port | ### Validity dates Where the checked moment falls in the certificate's lifetime. | Id | Severity | Title | Source | What it means | Fix | | --- | --- | --- | --- | --- | --- | | expiry | FAIL | Expired N days ago | [RFC 5280, 4.1.2.5](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5) | Full-page warning; API clients refuse | Renew and reload | | expiry | FAIL | Not valid yet | [RFC 5280, 4.1.2.5](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5) | Refused until the start date, or the server clock is wrong | Check the clock or wait | | expiry | CHECK | Renew soon: N days left | none (Tamperbox) | Inside the last third; renewal should have run | Check the renewal job and the reload | | expiry | PASS | N days left | [RFC 5280, 4.1.2.5](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5) | | | | lifetime | CHECK | Valid for N days | [BR 6.3.2](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#632-certificate-operational-periods-and-key-pair-usage-periods) | Longer than the public limit for its issue date; private authority | Use a public authority, or install the private root everywhere | ### Chain order and completeness What the server sends with its certificate, and in what order. | Id | Severity | Title | Source | What it means | Fix | | --- | --- | --- | --- | --- | --- | | first | CHECK | Your certificate was not first | [RFC 9846, 4.5.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1) | Pasted chain started with an issuer | Serve your certificate first | | order | CHECK | Chain is out of order | [RFC 9846, 4.5.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1) | Present but misordered | Serve your certificate, then each issuer in turn | | order | FAIL | Chain has a gap | [RFC 9846, 4.5.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1) | A link is missing | Serve the full chain | | incomplete | CHECK or FAIL | Intermediate not sent | [RFC 9846, 4.5.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1) | Only the server's own certificate was sent | Serve the full-chain file | | root | INFO | Root certificate sent | [RFC 9846, 4.5.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1) | Allowed, but extra bytes per handshake | Remove the root from the chain file | | ca-expiry-n | CHECK | X expires first | [RFC 5280, 6.1.3](https://www.rfc-editor.org/rfc/rfc5280#section-6.1.3) | An intermediate ends before your certificate | Renew onto the issuer's current chain | ### Key, signature and protocol The cryptography of the certificate and of this connection. | Id | Severity | Title | Source | What it means | Fix | | --- | --- | --- | --- | --- | --- | | key | FAIL | N-bit RSA key | [BR 6.1.5](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#615-key-sizes) | Current clients refuse RSA under 2048 bits | Reissue with 2048-bit RSA or P-256 | | key | PASS | The key, by type | [BR 6.1.5](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#615-key-sizes); none for Ed25519 and Ed448 | Meets current recommendations | | | key | INFO | The key, by type | none | Key strength could not be established | | | signature | FAIL | Signed with SHA-1 or MD5 | [RFC 9846, 4.5.1.3](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.3) | Refused since 2017 | Reissue; every current authority signs with SHA-256 or stronger | | protocol | FAIL | TLS 1.0 or 1.1 negotiated | [RFC 8996, 4 and 5](https://www.rfc-editor.org/rfc/rfc8996#section-4) | Removed from browsers in 2020 | Enable 1.2 and 1.3, disable the rest | | protocol | PASS | TLS 1.2 or 1.3 negotiated | [RFC 9846](https://www.rfc-editor.org/rfc/rfc9846) | | | | group | PASS, CHECK or INFO | The key exchange group | none (Tamperbox); field from [RFC 9846, 4.3.7](https://www.rfc-editor.org/rfc/rfc9846#section-4.3.7) | Post-quantum hybrid, obsolete draft, or classical | See the post-quantum checker | ## Guide Each situation the tool can put you in, with the steps and how to confirm the fix. After every fix, check the host again: the chain section should show the new certificate's dates, and the finding should be gone. ### Renew soon The certificate works, but renewal did not replace it when it should have. 1. Check the renewal job. For certbot: `certbot renew --dry-run`. For acme.sh: `acme.sh --cron --force`. For a hosting panel: its certificate page shows the last attempt and its error. 2. If a new certificate was issued but the page still shows the old dates, the server has not reloaded it. Reload or restart the service and check again. 3. If renewal fails, read the error. The usual causes: the DNS for the host changed, `/.well-known/acme-challenge/` is blocked or redirected, the DNS API token for a DNS-01 challenge expired, or the port used by the challenge is closed. 4. If the authority rate-limited you after repeated failures, wait the stated period before retrying. Confirm: the time axis shows a bar that ends well after today, with the vertical mark outside the hatched renewal window. ### Expired, or not valid yet Every visitor is affected until a valid certificate is served. 1. Issue a new certificate and install it with its intermediates (the "fullchain" file). 2. Reload the server. Check the host: the chain should show today inside the new validity window. 3. Then fix the renewal job so it does not happen again (previous section). "Not valid yet" with a start date in the past hours usually means the server's clock is behind. Fix the clock, not the certificate. ### Intermediate not sent The site looks fine in a desktop browser and fails in a phone, a script or a mail server. 1. Find the chain file your issuer or ACME client wrote: `fullchain.pem` (certbot), `fullchain.cer` (acme.sh), or the bundle your authority sent with the certificate. 2. Point the server at it. nginx: `ssl_certificate /path/fullchain.pem;`. Apache: `SSLCertificateFile` with the full chain, or `SSLCertificateChainFile` for the intermediates. HAProxy: concatenate certificate, intermediates and key into one file. 3. Reload. The chain section should now show two or three certificates with no ghost row. Verify from the command line: `openssl s_client -connect host:443 -servername host -showcerts </dev/null` prints every certificate the server sent; a complete chain has more than one. ### Does not name this host The certificate is valid but was issued for other names. 1. Open Names it covers. If the name you need is missing, reissue the certificate with that name added, or serve the certificate that was issued for it. 2. If the name is present under a wildcard but still not covered, remember that `*.example.com` covers one label: `app.eu.example.com` needs its own name. 3. If the names look right but the probe still gets a different certificate, the server is picking its default virtual host because no server block matches the SNI name. Check the `server_name` or `ServerName` for this host. ### Self-signed, or an untrusted root No public authority vouches for the certificate. Browsers warn; clients connect only when told to trust this exact certificate. - For a public host: replace it with a certificate from a public authority. ACME authorities issue them free. - For an internal host: this is expected. Install the private root on every client that connects, and ignore the trust finding here; the rest of the findings still apply. ### Weak key, weak signature - An RSA key under 2048 bits, or a SHA-1 signature: generate a new key (2048-bit RSA or, better, ECDSA P-256) and reissue. Never reuse the old key. Every current authority signs with SHA-256 or stronger, so a fresh issuance fixes the signature as well. - A weak key in an intermediate: reissue onto the authority's current chain. ### TLS 1.0 or 1.1 negotiated The server offers only old protocol versions, or the probe was steered to one. 1. Enable TLS 1.2 and 1.3 and disable 1.0 and 1.1. nginx: `ssl_protocols TLSv1.2 TLSv1.3;`. Apache: `SSLProtocol -all +TLSv1.2 +TLSv1.3`. HAProxy: `ssl-default-bind-options ssl-min-ver TLSv1.2`. 2. Restart and check again. Connection should show TLS 1.3, or 1.2. ### Checking a mail server Add the port: `mail.example.com:25` for inbound SMTP with STARTTLS, `:465` or `:587` for submission, `:993` for IMAP. Mail certificates fail in the same ways as web ones, with one difference: the name to cover is the host in the MX record or the client configuration, not the mail domain. `mail.example.com` must be in the certificate even when the domain is `example.com`. A mail server's certificate is one of three things a sending domain gets judged on; the other two are its [DKIM keys](https://docs.tamperbox.dev/tools/dkim-checker/) and its DMARC policy ([DMARC checker](https://tamperbox.dev/dmarc-checker)). ### Reading a pasted chain To judge a chain without connecting (a file from a colleague, a chain from an internal host, a certificate before deployment): 1. Paste the PEM blocks, or openssl output with `-showcerts`. 2. Set Host name to match to the host it will serve, so the name finding is real. 3. Set Check dates on to the day you care about: deployment day, or the day after expiry to see what breaks. 4. Trust is not checked for pasted chains. Check the host live once it is deployed. ### Break it cases Each case is built from your own input where that is possible, so the finding looks the way it would for you. | Case | What it loads | What to look at | | --- | --- | --- | | Wrong host name | Your chain, matched against `beta.app.` + your host | Names it covers, with no match | | The day after it expires | Your chain, judged the day after its end date | The time axis with the mark past the bar; Expired finding | | Intermediate left out | Your certificate alone | The ghost row; Intermediate not sent | | Chain out of order | Your chain with the issuers reversed | Chain is out of order; Heal it offers to reorder | | Self-signed | The sample's self-signed certificate | Self-signed label; trust finding | | Weak key, TLS 1.2 | The sample's legacy host: 1024-bit RSA over TLS 1.2 | Key finding; Connection | Heal it after a break offers "Restore input before this break", or "Put the chain in order" for the misordered case. History records each step with Revert. ## Worked example The page opens on `tamperbox.dev` and runs the same live server-side check used for any host you enter. The certificate, chain, address, negotiated cipher and expiry change over time, so the opening result is deliberately not a frozen fixture. Read it like any other result: - The verdict reports whether the probe verified the current chain. - The certificate axis shows exactly what `tamperbox.dev` served during that connection. - The names section marks the DNS name that covers `tamperbox.dev`. - The Connection section records the protocol, cipher, key exchange, address and check time observed by the probe. Replace `tamperbox.dev` with your own host in the box on the left and every section, card and link is rewritten for it. Reserved `harbor-supply.example` fixtures remain in the mail-oriented tools and deliberate Break it cases, where a stable synthetic record or failure is more useful than a live lookup. ## For agents The Tamperbox MCP server runs the same checks. Search its catalog for the certificate or TLS operation, inspect the input schema, and call it with the host name. The result carries the findings with their ids and severities as listed in the [finding reference](#finding-reference), and a warning block that must be kept with any conclusion drawn from it: - The probe observed one connection from one location. It does not prove what another client, in another region, negotiates. - Trust is the probe's trust store, not a browser's. - Revocation is not checked. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern, and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the host name travels. ## Limits - One connection, from one location, at one moment. Other servers behind the same name, other regions and other moments can differ. - Only the protocol, cipher and group this connection negotiated are known, not everything the server allows. - Revocation (OCSP and CRL) is not checked, and neither is Certificate Transparency. - Pasted certificates and pasted verification codes are reported as supplied, not independently verified. - Lifetime guidance uses the start date as an estimate of the issuance date; the actual issuance time is not recorded in a certificate. - The page's own rules do not verify signatures; a pasted chain is linked by names only. - The key exchange group, ALPN and the post-quantum link are reported for port 443 only. - Nothing is stored. ## References - [RFC 9846, The Transport Layer Security (TLS) Protocol Version 1.3](https://www.rfc-editor.org/rfc/rfc9846). Proposed Standard, July 2026; obsoletes RFC 8446 (the earlier TLS 1.3 specification), RFC 5246 (TLS 1.2), 5077, 6961, 7627 and 8422. Sections used: [1.4](https://www.rfc-editor.org/rfc/rfc9846#section-1.4), [4.3.7](https://www.rfc-editor.org/rfc/rfc9846#section-4.3.7), [4.5.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1), [4.5.1.1](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.1) (not applied), [4.5.1.2](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.2), [4.5.1.3](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.1.3) and [Appendix C.2](https://www.rfc-editor.org/rfc/rfc9846#appendix-C.2). - [RFC 5280, Internet X.509 Public Key Infrastructure Certificate and CRL Profile](https://www.rfc-editor.org/rfc/rfc5280). Proposed Standard; updated by RFC 6818, 8398, 8399, 9549, 9598, 9608, 9618, 9925 and 10007. Sections used: [4.1.2.5](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5), [4.1.2.5.1](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.5.1), [4.2.1.6](https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6), [4.2.1.9](https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.9), [6.1](https://www.rfc-editor.org/rfc/rfc5280#section-6.1), [6.1.3](https://www.rfc-editor.org/rfc/rfc5280#section-6.1.3) and [7.1](https://www.rfc-editor.org/rfc/rfc5280#section-7.1) (not applied). - [RFC 9525, Service Identity in TLS](https://www.rfc-editor.org/rfc/rfc9525). Proposed Standard, November 2023; obsoletes RFC 6125. Sections used: [2](https://www.rfc-editor.org/rfc/rfc9525#section-2), [4.1](https://www.rfc-editor.org/rfc/rfc9525#section-4.1), [6.3](https://www.rfc-editor.org/rfc/rfc9525#section-6.3) and [6.6](https://www.rfc-editor.org/rfc/rfc9525#section-6.6). - [RFC 8996, Deprecating TLS 1.0 and TLS 1.1](https://www.rfc-editor.org/rfc/rfc8996). Best Current Practice, BCP 195. Sections used: [4](https://www.rfc-editor.org/rfc/rfc8996#section-4) and [5](https://www.rfc-editor.org/rfc/rfc8996#section-5). - [RFC 6066, TLS Extensions: Extension Definitions](https://www.rfc-editor.org/rfc/rfc6066). Proposed Standard; updated by RFC 9846. Section used: [3](https://www.rfc-editor.org/rfc/rfc6066#section-3). - [RFC 7301, TLS Application-Layer Protocol Negotiation Extension](https://www.rfc-editor.org/rfc/rfc7301). Proposed Standard. Section used: [3.1](https://www.rfc-editor.org/rfc/rfc7301#section-3.1). - [RFC 3207, SMTP Service Extension for Secure SMTP over Transport Layer Security](https://www.rfc-editor.org/rfc/rfc3207). Proposed Standard. Section used: [4](https://www.rfc-editor.org/rfc/rfc3207#section-4). - [RFC 8555, Automatic Certificate Management Environment (ACME)](https://www.rfc-editor.org/rfc/rfc8555). Proposed Standard. Cited for context in the renewal guidance; no section is applied as a rule. - [RFC 6962, Certificate Transparency](https://www.rfc-editor.org/rfc/rfc6962), Experimental, obsoleted by [RFC 9162, Certificate Transparency Version 2.0](https://www.rfc-editor.org/rfc/rfc9162), Experimental. Cited only to say that CT is not checked. - [CA/Browser Forum, Baseline Requirements for the Issuance and Management of Publicly-Trusted TLS Server Certificates](https://cabforum.org/working-groups/server/baseline-requirements/requirements/). Industry requirements for public authorities, version 2.3.1, 4 October 2026. Sections used: [6.1.5](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#615-key-sizes), [6.3.2](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#632-certificate-operational-periods-and-key-pair-usage-periods), [7.1.2.7](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#7127-subscriber-server-certificate-profile), [7.1.2.7.12](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#712712-subscriber-certificate-subject-alternative-name) and [7.1.3.2](https://cabforum.org/working-groups/server/baseline-requirements/requirements/#7132-signature-algorithmidentifier). --- # Subdomain Finder How Tamperbox extracts DNS names from public Certificate Transparency observations and labels risky-looking names. Canonical: https://docs.tamperbox.dev/tools/subdomain-finder/ Updated: 2026-10-25 Applies to: tamperbox.dev, October 2026 Prerequisites: a domain name or pasted crt.sh-style JSON or name text Outputs: normalised names, wildcard entries, internal-looking labels, truncation state and source limitations Limitations: Public observations are time-sensitive and do not prove ownership, intent or private configuration The tool page is [tamperbox.dev/subdomain-finder](https://tamperbox.dev/subdomain-finder). It opens with a deterministic local example; replace it to inspect your own target. This guide documents the actual input path, evidence contract, classifications and independent verification steps. <div class="tb-callout"><strong>Where processing happens:</strong> input cleanup, pasted-data parsing and report rendering happen in the browser. Live checks send only the validated public target to the Tamperbox server and the public services required for the lookup. The page stores no report; History is local to the current browser session.</div> ## What the tool answers The checker answers which names appear in a bounded Certificate Transparency result or pasted certificate-name set beneath a domain. Its conclusion is deliberately narrower than an ownership or security claim. A displayed provider, product, name or passing check means that the listed public evidence matched a documented rule at the observation time. Every conclusion is paired with evidence. The opening verdict is a summary for orientation, while Findings contains the actionable interpretation and the later result sections retain the underlying records, addresses, fields or names. If a conclusion matters operationally, verify that evidence through an authoritative account or an independent standards-aware client before changing production. ## Inputs ### Accepted source Enter a bare domain for a live certificate-transparency search, or paste crt.sh JSON for local parsing. A JSON object is accepted as one row; arrays contain multiple rows. The parser reads `name_value` and `common_name`, and infers the most common final two-label suffix for pasted rows. That heuristic is not a public-suffix-aware ownership boundary. Plain text produces an informational result and can offer Heal it to retain extracted names without inventing dates or issuers. Text files are read in the browser. The resulting input follows the same classification rules as the field; reading a file locally does not make a domain or public-IP lookup offline. Cleanup keeps an already accepted record intact and otherwise tries unwrapping a single-line address. Unusable text remains visible for correction. ### When work runs Domain input runs after a 600-millisecond typing pause. Enter runs it immediately; pasted records run immediately. Drops and page-wide paste use the same input loader. Leaving the field applies cleanup and reruns only when cleanup changes the text. Each edit aborts the previous request and increments a generation marker. A slower old response therefore cannot replace a newer result, and clearing the source immediately clears copyable output. The opening input uses the same parser and processing path as a replacement. The reserved `harbor-supply.example` certificate rows are a local synthetic example and send no CT request. ## Reading the result ### Verdict and privacy The verdict states what the available evidence supports and uses pass, check, fail or informational status consistently. Pass means the bounded rule succeeded. Check means a human should confirm context. Fail means a concrete operational rule was violated. Info describes a limitation, absence or neutral fact and must not be promoted into success or failure by an automated reader. Two privacy lines distinguish browser-only work from live lookup work. The Checked line names the cleaned input and source mode. Copy result is hidden while work is pending, after an error and when input is empty, preventing a stale report from being exported as current. ### Findings and evidence Findings are ordered with failures first, then checks, informational notes and passes. Repeated passing details can fold into a disclosure so that exceptions remain visible. Each item states the observation and its consequence; any remediation is scoped to the evidence rather than presented as a universal configuration recipe. Evidence sections follow Findings and precede History. They are the audit trail for the verdict. A provider label derived from a catalog remains an inference, while a literal record or response field remains an observation. This distinction matters when signatures are incomplete, white-labelled or stale. ### History and handoffs History records intentional input replacements, including Break it examples and their repairs. Revert restores the prior input and runs it again, including live requests when applicable; Reset input returns to the value at the beginning of the recorded sequence. History is not monitoring, persistence or an account log. Check the rest carries the current input to other tools in Domains & hosting. Take it further sends the first flagged name to the [Website Hosting Checker](https://docs.tamperbox.dev/tools/website-hosting/), [CDN and Proxy Detector](https://docs.tamperbox.dev/tools/cdn-detector/) or [Website Technology Detector](https://docs.tamperbox.dev/tools/website-technology/). No such links appear when there is no flagged name. These checks collect new evidence about that one name; they do not scan the entire certificate-name list. A receiving tool runs its own check; agreement is not guaranteed. Explicit tool links transfer the input through temporary browser `sessionStorage` and, when needed, a same-origin browser channel. The URL fragment contains a random transfer token, not the input. Transfers are accepted for less than one minute, consumed once, and bound to the destination path. The destination removes the token from its address. Ordinary documentation links and direct visits do not restore a previous input; if transfer storage is unavailable, the link still opens the tool. ## Method ### Validation and collection Before collection, the same domain validation runs in the browser and on the server boundary. Requests are restricted to supported public DNS names and HTTPS roots, redirects are bounded, response sizes are capped and abort signals are propagated. These limits make the observation reproducible and prevent an entered value from becoming an unrestricted network fetch. Use the input modes above to determine which requests run. DNS evidence comes from a public recursive view and can reflect cache state. Local classification cannot add observations absent from the supplied evidence. A server lookup is a fresh observation, not confirmation that cached or pasted evidence is still current. ### Classification rules Live mode requests a bounded CT-search representation and parses certificate name values. Pasted JSON uses the same shape; plain text is split locally. Names are lower-cased, wildcard prefixes are retained separately, invalid or unrelated names are discarded and exact duplicates are removed. [RFC 9162 section 1](https://www.rfc-editor.org/rfc/rfc9162#section-1) describes CT as a way to audit certificate issuance; it does not define a complete current inventory. No confidence percentage is invented. When sources disagree, the disagreement is a finding. When a source is unavailable, the affected conclusion becomes informational or inconclusive rather than silently using a previous result. Catalog matches are exact bounded rules; unknown is a valid outcome. ### Ordering and export The renderer calculates all findings from the current observation before updating the verdict, chips, evidence and landing cards. Status priority is fail, check, info, pass. Stable secondary ordering keeps repeated runs readable without changing severity. The Markdown mirror and Copy result output preserve input, summary, findings and important evidence in text form. They do not embed secrets, browser state or the expanded educational cards. Agents should cite the observation time and limitation alongside any exported conclusion. ## Standards and conformance ### Applied specifications | Source | Rule used | Boundary | | --- | --- | --- | | [RFC 9162 section 1](https://www.rfc-editor.org/rfc/rfc9162#section-1) | CT logs make certificate activity auditable | The tool consumes a search view, not every log directly | | [RFC 9162 section 2.1.1](https://www.rfc-editor.org/rfc/rfc9162#section-2.1.1) | Logs accept certificate-chain submissions | Observed names can be historical | | [RFC 6125 section 6.4](https://www.rfc-editor.org/rfc/rfc6125#section-6.4) | Wildcard identifiers have constrained matching semantics | Wildcards are displayed distinctly and never expanded into hosts | | [RFC 1034 section 4.3.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.3.2) | DNS existence is answered by current resolution | CT names are not resolved by this tool | These references define the records and message semantics, not the provider catalogs. A catalog is product logic and can lag branding, acquisitions or custom deployments. Where a standard permits several valid configurations, the tool reports the observed form and avoids declaring one commercial pattern universally correct. ### Where conformance stops The checker is an observer, not an authoritative DNS server, browser, certificate monitor, mail receiver or provider control plane. It does not claim protocol conformance for the target. It applies selected validation and interpretation rules to bounded evidence and exposes the boundary where a fuller protocol operation would begin. The phrase “public” refers to the server's Internet view. Private split-horizon answers, authenticated dashboards and regional routing can differ. Cached answers can remain until TTL expiry, and HTTP intermediaries can transform what the origin sent. ## Finding reference ### Emitted findings | Finding | Severity | Meaning | Repair or next check | | --- | --- | --- | --- | | Names found | Pass | Unique in-scope names were extracted | Resolve and verify a name before relying on it | | Looks internal | Check | A label resembles admin, staging, dev, vpn or another sensitive role | Confirm exposure and certificate need with the owner | | Wildcard observed | Info | A certificate identifier covers a label level | Do not assume every possible expanded name exists | | Results truncated | Info | The configured limit was reached | Narrow the search or query logs independently | | Broken JSON | Fail | Pasted structured input cannot be parsed | Export valid JSON or paste names as text | | Expected crt.sh JSON | Info | Structured input had the wrong top-level shape | Supply an array containing name_value fields | | No names found | Info | No usable in-scope name was extracted | Check the domain, source availability and other inventories | Wording can include the observed name, count, provider or status. Automated consumers should use the supplied status and evidence rather than parsing the English title as a permanent identifier. A missing finding is not evidence that the corresponding external condition is absent when its source could not be collected. ### Status handling | Status | Consumer action | What not to infer | | --- | --- | --- | | Pass | Preserve the evidence and continue normal review | Permanent correctness, ownership or availability | | Check | Confirm intent and inspect the named evidence | Definite compromise or outage | | Fail | Prioritise the concrete broken rule and verify independently | That every user sees the same failure | | Info | Carry the limitation or neutral fact with the report | Success merely because no failure was emitted | ## Guide ### Verify independently Start with an authoritative or widely used command-line client. For DNS, use `dig` with the exact record type and compare every returned owner, target and TTL. Add `+trace` only when delegation matters; a trace and a recursive answer solve different questions. For HTTPS, use `curl -I --location https://host/` and retain each hop and response field. For certificates, use an established TLS client and a CT monitor you trust. Repeat from another network when geography or split routing could matter. Save the observation time and the original evidence before editing. After a DNS change, wait at least the prior TTL and then query both the intended authorities and independent recursive resolvers. ### Repair safely Do not delete an unfamiliar record or reroute a public name merely because a catalog labels it. First identify the owning service, deployment repository or provider account. Confirm whether the item is current, a migration remnant, a failover path or a delegated responsibility. Make the smallest reversible change, keep the prior value, and have a rollback trigger. Re-run this page after propagation, then verify the user-visible service. A clean public lookup cannot prove application health. Conversely, an informational unknown does not require a speculative change. ### Diagnose conflicting evidence When two signals disagree, ask whether they describe different layers: apex versus www, resolver cache versus authority, CDN edge versus origin, entered host versus redirected host, or certificate history versus current DNS. Compare literal evidence before comparing labels. The disagreement itself often reveals a migration or intermediary. If a lookup fails, preserve the error and retry once. Repeated timeouts are not equivalent to empty data. Use the specialist tool linked by the finding for deeper parsing rather than converting an inconclusive aggregate result into a failure. ### Break it and heal it The cards distinguish certificate rows from plain text or broken JSON. Names recovered from text have no inferred issuer or validity dates. A currently valid certificate in the supplied rows does not establish that the named service is online; wildcard coverage is not an enumeration of hosts. The Break it controls create documented edge cases from the visitor's own input or a reserved fixture. They are teaching states, not scans. Heal it restores a safe derived value when the repair is deterministic. Revert remains available when several changes have been made. Use these cases to learn how invalid, missing, mixed or stale evidence appears before diagnosing production. The control never edits DNS, hosting, certificates or provider accounts. ## Worked example The opening fixture is `harbor-supply.example`, a reserved synthetic dataset. It always demonstrates ordinary, wildcard and internal-looking names without depending on a sometimes slow third-party CT search. Entering a real domain switches to the live lookup. Read the example from verdict to Findings, then compare the literal evidence. Open one Break it case and use Heal it or Revert. Finally, replace the default with a domain you are authorised to assess. This sequence demonstrates both the successful path and the failure contract without implying that the named public domain endorses the tool. ## For agents Agents can discover the `subdomain_finder` operation through Tamperbox MCP. The browser page id `subdomain-finder` is not the operation name. The server operation and browser renderer can expose different fields; inspect the operation schema before supplying arguments. Preserve the result's distinction between observed evidence, catalog inference and limitation. State whether the run was live or pasted, include the cleaned target and observation time, and never turn “not found” into “does not exist” unless the method truly establishes that condition. Choose a specialist operation when the task is narrow. Use this page's report when its combined view or educational findings add value. Do not pass credentials, private hostnames or customer data into a public lookup. If a repair would change production, present the exact evidence, expected effect, propagation window and rollback before acting. Machine readers should branch on status and structured fields where available, not English punctuation. Treat network and parse errors as inconclusive. Re-run after a meaningful interval rather than repeatedly polling a third-party source. ## Limits CT records certificates, not present DNS or ownership. A name may be expired, revoked, transferred, private behind split DNS or never deployed. Not every certificate is necessarily visible through one search service, rate limits can interrupt live lookup, and wildcard entries cannot be enumerated into real hosts. No connection or port scan occurs. All outputs are point-in-time observations. Resolver caching, negative caching, anycast, geo steering, redirects and intermittent upstream failures can change a later run. The service does not retain a monitoring history or notify on change. Local History is an interaction aid, not durable evidence. No result grants permission to probe a target or modify it. Use authorised accounts and owner-approved procedures for deeper checks. Where business, security or legal decisions depend on attribution, obtain confirmation from the responsible provider or domain operator. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034), Domain Names — Concepts and Facilities, especially [section 4.3.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.3.2) for resolver behavior. - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035), Domain Names — Implementation and Specification, especially [section 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1) for resource-record types and classes. - [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110), HTTP Semantics, especially [section 3.7](https://www.rfc-editor.org/rfc/rfc9110#section-3.7) for intermediaries and [section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) for status codes when HTTP evidence is collected. - [Tamperbox Subdomain Finder](https://tamperbox.dev/subdomain-finder), the interactive tool and current Markdown mirror. --- # Tamperbox documentation Inspect public network evidence, transform structured text, and compose supported checks with Tamperbox. Canonical: https://docs.tamperbox.dev/ Updated: 2026-10-19 Applies to: MCP 0.2.0 Outputs: A path to the relevant Tamperbox tool, API operation, or MCP workflow Limitations: This documentation base does not replace the operation schemas bundled with the MCP server. Tamperbox gives developers browser tools and server-side diagnostics with explicit data-handling labels. Its MCP server lets an agent search the exact API contract, then run a small JavaScript workflow against documented operations. <div class="tb-doc-grid"> <a class="tb-doc-card" href="https://docs.tamperbox.dev/getting-started/"><strong>Start with one check</strong><span>Choose the browser, API, or MCP path and verify a small result.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/mcp/"><strong>Connect an agent</strong><span>Use the two-tool code-mode server from Codex, Claude, VS Code, or another MCP client.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/workflows/"><strong>Compose a workflow</strong><span>Discover schemas first, preserve warnings, and combine only compatible outputs.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/reference/operations/"><strong>Browse capabilities</strong><span>Find transforms, DNS, email, TLS, HTTP, network, and utility operations.</span></a> </div> ## Choose the right surface Use the browser tools at [tamperbox.dev](https://tamperbox.dev) when you want a visual workflow or local processing; each documented tool's method, finding reference and repair guide are under [Tool pages](https://docs.tamperbox.dev/tools/). Use the API when an application needs a single documented operation. Use the MCP server when an agent needs to discover schemas and compose calls. <div class="tb-callout"><strong>Data boundary:</strong> browser-local tools keep supported inputs on the device. Server checks and MCP API calls send their operation inputs to the configured Tamperbox API.</div> ## What this site covers - Setup for the public MCP server and local stdio package - Code-mode discovery and execution patterns - Operation families and input shapes - Limits, evidence boundaries, security, and privacy - Contribution paths for the public documentation repository ## Product sources The [Tamperbox MCP repository](https://github.com/oceanrescue/tamperbox-mcp) remains the source of truth for package behavior, versioned schemas, tests, and deployment records. This site turns those contracts into task-focused guidance. --- # Tamperbox MCP A code-mode MCP server with two tools over a documented catalog of Tamperbox operations. Canonical: https://docs.tamperbox.dev/mcp/ Updated: 2026-10-19 Applies to: MCP 0.2.0 Prerequisites: An MCP-compatible client Outputs: A clear choice between bundled search and API-backed execution Limitations: The MCP catalog covers API operations, not every interactive browser mode. Tamperbox MCP exposes two tools: `search` and `execute`. Both accept an async JavaScript function body. The smaller interface lets agents inspect exact schemas before they send inputs to the API. ## Tool model ### `search` Runs against the bundled OpenAPI document. It exposes `spec` and a resolved `operations` array. It does not call the Tamperbox API, and `apiCalls` stays at `0`. ### `execute` Runs code in an isolated QuickJS WebAssembly environment. The code can call documented endpoints through `tamperbox.request({ method, path, query?, body? })`. ```js const result = await tamperbox.request({ method: 'POST', path: '/v1/tools/dns_lookup', body: { name: 'example.com', type: 'A', resolver: 'google' }, }); return result; ``` ## Transports The package supports stdio for local clients and Streamable HTTP for hosted integrations. The public production endpoint is `https://mcp.tamperbox.dev/mcp`. ## What it does not do The server cannot call arbitrary URLs, add arbitrary headers, publish DNS changes, send email, or establish JWT trust through decoding. Unknown routes and arguments are rejected against the bundled contract. --- # TCP Ping How TCP Ping measures connect time to a host and port from three regions, how each attempt is classified, what every verdict and finding means, and how to fix refused, filtered and lossy ports. Canonical: https://docs.tamperbox.dev/tools/tcp-ping/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A host name or public IP address that resolves only to public addresses, and a TCP port (443 when left out) Outputs: A verdict per region (open, refused, no answer), every attempt with its connect time, a comparison of average connect times and the address tested Limitations: TCP handshake time from three broad regions, not ICMP ping and not your own latency; only the first resolved address is tested; a timeout is inconclusive; UDP cannot be tested The tool page is [tamperbox.dev/tcp-ping](https://tamperbox.dev/tcp-ping). It opens with `tamperbox.dev:443` ready to check and measures it only when you press Ping or Enter. This page is the long version: what each region does, how an attempt is classified, what each verdict and finding means, and how to confirm a fix without Tamperbox. <div class="tb-callout"><strong>Where processing happens:</strong> typing sends nothing. Names under the reserved <code>.example</code> zone, which the Break it fixtures use, are answered in your browser from fixed sample measurements. Pressing Ping or Enter sends the host and port to the Tamperbox server, which asks one measurement server in each chosen region to connect. No application bytes are sent over the connections and results remain in page memory.</div> ## What the tool answers 1. **Does the port accept connections?** From each region: open, refused, or no answer. 2. **Is it reliable?** Did all three attempts connect, or were some lost? 3. **How far away is it?** The connect time per region, which grows with network distance. 4. **What exactly was tested?** The address the name resolved to, and any other addresses that were not tested. ## Inputs ### A host and port `example.org:443`, `example.org` (port 443 is assumed), `203.0.113.10:22`, `[2001:db8::10]:443` for an IPv6 address with a port, or a bare IPv6 address. A pasted link is reduced to its host and port (`https://example.org:8443/path` becomes `example.org:8443`), and the hint says what was kept. Near misses get a Heal it repair instead of a measurement: - a space where the colon belongs (`example.org 22` offers `example.org:22`); - a path after the host (`example.org/login` offers `example.org`); - a port outside 1 to 65535 offers port 443. Private (RFC 1918), loopback, link-local, unique local and carrier-grade NAT addresses are refused in the browser, because no server on the internet can reach them. The documentation ranges of [RFC 5737](https://www.rfc-editor.org/rfc/rfc5737#section-3) and [RFC 3849](https://www.rfc-editor.org/rfc/rfc3849#section-2) are accepted by the page so that examples read naturally, and refused by the server. ### Regions Eastern North America, Western Europe and Asia Pacific, all selected by default. At least one region always stays selected. Changing the selection stages a new test; it does not run until you press Ping. ### When it runs Only on Enter or the Ping button. Adding or removing spaces around the input keeps the current result. A changed target says what will be tested and waits. A sample name under `.example` runs at once because it costs nothing. ## Reading the result ### Verdict and chips The verdict sentence is one of: | Verdict | When | | --- | --- | | Reachable from all N regions | Every measured region connected on every attempt | | Reachable …, with lost attempts | Every region connected, but at least one lost an attempt | | Reachable from N of M regions | Some regions connected, the others refused or did not answer | | Refused from every region | Every measured region reported refusal on its completed attempts | | No answer from any region | Nothing connected and the answers were not all refusals | | Measured N of M regions | Some regions did not complete the measurement; their reachability is unknown | | Measurements are unavailable | No region completed | | Target not tested | The server refused the target under the public-address rule | The detail line names the fastest and slowest regions. One chip per region gives its average time or its state; each chip scrolls to the region cards. ### Findings Directly under the verdict, worst first; the [Finding reference](#finding-reference) lists them all. ### By region One card per region: its state, the average connect time, the three attempts (each a time, "Refused", "No answer", "Unreachable", "Failed" or "Cancelled") and the minimum and maximum. ### Average connect time A bar per region for the regions that connected, with the fastest marked. ### What was tested The host, the port, the address tested, and any other addresses the name resolves to, marked "not tested". ### History History records input changes made by Break it and Heal it. It appears after the complete result and before Take it further. Revert undoes the newest change; Reset input returns to the input before the first retained change. Restore input before this break is also available in Heal it when there is a change to undo. Restoring does not create another history entry. This history is held in the page and disappears on reload. Restoring a live target stages it for the run button; reserved samples can render immediately. Typing or pasting a different input starts a new history. ### Take it further These links carry values derived from the current result. A link is absent when its required evidence is missing; the tool does not invent a target. | Destination | Value and condition | | --- | --- | | [ASN Lookup](https://docs.tamperbox.dev/tools/asn-lookup/) | The address tested | | [TCP Ping](https://docs.tamperbox.dev/tools/tcp-ping/) | The first other resolved address on the same port, for live results | | [SSL Checker](https://docs.tamperbox.dev/tools/ssl-checker/) | The hostname and port after a successful live connection on 443, 465, 993, 995 or 853 | | [Reverse DNS](https://docs.tamperbox.dev/tools/reverse-dns/) | The address tested, for live results | Reserved sample results offer only the derived links supported by local sample data. A live destination applies its own input rules; measurement tools still wait for an explicit run. ### What this result means Six cards explain the current findings: Ask your agent, In plain words, What does it mean?, What good looks like, How to fix it, and Tool limitations. Expand a card to read the explanation and its method or guide link. Copying an agent prompt does not run another check. The cards interpret the evidence already shown; they are not an additional measurement or an independent confirmation. When the input is cleared, a check fails, or no result is available, result-specific cards clear and contextual links disappear. Read the verdict before relying on a card, and distinguish a missing observation from a confirmed negative result. ## Method ### 1. Resolution in each region Each chosen region resolves the name on its own, in parallel with the others. Every address in the answer must be public and the answer must hold between 1 and 64 records; otherwise the region tests nothing and reports the target as refused under that rule. Up to eight distinct addresses are kept and the first is tested. Because each region resolves separately, a name with location-dependent answers can be tested at different addresses in different regions; the What was tested panel shows the address used by the first region that completed. DNS time is not part of any connect time. ### 2. Three attempts Each region opens three TCP connections in sequence to the chosen address and port, each limited to 1.5 seconds, and the whole region, resolution included, must finish within 7 seconds. An attempt that completes the three-way handshake ([RFC 9293, section 3.5](https://www.rfc-editor.org/rfc/rfc9293#section-3.5)) is closed at once; no application data is sent; the service can still observe and log the accepted connection. The time recorded is from calling the socket connection function until its connect event: close to one network round trip from that region plus a little local overhead. Each attempt is classified from the socket outcome: | Attempt | Socket outcome | Meaning | | --- | --- | --- | | A time in ms | Handshake completed | The port accepts connections | | Refused | `ECONNREFUSED`: a reset came back | Something answered and said no. [RFC 9293, section 3.5.2](https://www.rfc-editor.org/rfc/rfc9293#section-3.5.2): "A SYN segment that does not match an existing connection is rejected by this means" | | No answer | No reply within 1.5 seconds | Dropped somewhere, or the host is down | | Unreachable | `ENETUNREACH` or `EHOSTUNREACH` | A router reported no route | | Failed, Cancelled | Any other error, or the region's time ran out | Not classified further | ### 3. Region state A region is **Open** when at least one attempt connected, **Refused** only when all completed attempts were refused and at least one attempt completed, and **No answer** otherwise. Mixed refusals and timeouts count as no answer, because together they are inconclusive. Average, minimum and maximum are taken over the attempts that connected; the average is rounded to hundredths of a millisecond, and the page shows one decimal under 10 ms. ### 4. Findings | Rule | Condition | Finding | | --- | --- | --- | | Refused | Any region refused on all attempts | FAIL | | Silent | Any measured region connected on no attempt and was not refused | CHECK | | Lossy | Any region connected on some but not all attempts | CHECK | | Unsafe target | A region refused the target under the public-address rule | CHECK | | Other addresses | The name resolved to more than one address | INFO | | Region unavailable | A region did not complete for another reason | INFO | | Connect time | Always | INFO | ### 5. Reading distance Light in fibre covers about 200 km per millisecond, so each 100 km of fibre adds about 1 ms of round trip (0.5 ms each way). Routes are longer than straight lines, so a server in Europe usually answers Asia Pacific in 150 ms or more. Similarly low times can be consistent with anycast or distributed endpoints, but timings alone cannot identify the topology. Compare each resolved address and the provider's deployment information. <span id="standards"></span> ## Standards and conformance | Specification | Sections used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 9293](https://www.rfc-editor.org/rfc/rfc9293) TCP | [3.5](https://www.rfc-editor.org/rfc/rfc9293#section-3.5), [3.5.2](https://www.rfc-editor.org/rfc/rfc9293#section-3.5.2), [3.5.3](https://www.rfc-editor.org/rfc/rfc9293#section-3.5.3) | A completed handshake is "open"; a reset in response to the SYN is "refused" | No data is exchanged; TCP options, window sizes and retransmissions are not reported. Obsoletes [RFC 793](https://www.rfc-editor.org/rfc/rfc793) | | [RFC 792](https://www.rfc-editor.org/rfc/rfc792) ICMP | Echo, Destination Unreachable | Not used: this is not ICMP ping. A host that answers ICMP may filter TCP, and the reverse | ICMP unreachable messages surface only as "Unreachable" when the operating system reports them | | [RFC 8305](https://www.rfc-editor.org/rfc/rfc8305) Happy Eyeballs v2 | [4](https://www.rfc-editor.org/rfc/rfc8305#section-4), [5](https://www.rfc-editor.org/rfc/rfc8305#section-5) | Explains why clients may use another address than the one tested | The tool tests one address only; enter the other as the host to test it | | [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3), [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598#section-4), [RFC 4193](https://www.rfc-editor.org/rfc/rfc4193#section-3) | as listed | Refused in the browser and on the server | | ## Finding reference | Finding | Severity | What it means for the people using the server | Fix | | --- | --- | --- | --- | | Refused from N regions | FAIL | Clients there get an immediate "connection refused" | Start the service, listen on a public interface, open the host firewall | | No answer from N regions | CHECK | Connections hang until they time out; inconclusive | Allow the port in the network firewall or security group; check geo-blocking | | Some attempts were lost | CHECK | Occasional slow or failed connections | Look for packet loss, connection limits or overload | | A region did not complete the test (unsafe target) | INFO | The name resolves to a non-public address or too many records | Fix the DNS records or test the public address | | N other addresses not tested | INFO | Clients may connect to another address, for example over IPv6 | Test each address as the host | | A region did not complete the test | INFO | That region's reachability is unknown | Press Ping again | | This is TCP connect time | INFO | Handshake time from the region, not your latency or ICMP ping | | ## Guide ### The port is refused 1. On the server, check that the service listens on the port and on a public address: ```sh ss -ltnp | grep ':443' ``` A line with `127.0.0.1:443` means it listens on localhost only; bind it to `0.0.0.0` or the public address. 2. Check the host firewall (`ufw status`, `firewall-cmd --list-all`, Windows Defender Firewall). 3. Press Ping again. A refused region should turn Open. ### No answer from some or all regions A timeout means the SYN or its answer was dropped. Look at the layer in front of the server: a cloud security group or network ACL, a firewall appliance, or a geo-blocking rule that differs by region. If only one region is silent, a rule or route specific to that region is the likely cause. ### Lost attempts Run the test a few times. Failures limited to one region suggest comparing paths; failures across regions suggest also checking the server or load balancer. Neither pattern uniquely identifies the cause. These are failed connection attempts, not a direct packet-loss measurement. ### Confirm without Tamperbox From a machine near the users who report problems: ```sh nc -vz -w 2 example.org 443 curl -o /dev/null -s -w 'connect %{time_connect}s\n' https://example.org/ ``` `nc` reports "succeeded" or "Connection refused" or a timeout, the same three outcomes as the tool. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | Refused everywhere | `closed.harbor-supply.example:8443` | A refusal from all three regions and the FAIL finding | | No answer (filtered) | `filtered.harbor-supply.example:22` | Timeouts everywhere and the inconclusive verdict | | Only Europe answers | `eu-only.harbor-supply.example:443` | One region open, two silent | | Lost attempts | `flaky.harbor-supply.example:443` | Regions that connect on some attempts only | | Private address | `192.168.1.20:22` | The refusal in the browser; nothing is sent | | Port out of range | your host with port 70000 | The port error and the repair to port 443 | ## Worked example The page starts with `tamperbox.dev:443` in the field and waits for Ping or Enter. No live probe is spent merely by loading or typing this target. Select the regions and run it, then inspect each region independently: the resolved address, successful attempts, individual outcomes and average connect time. A region that connects proves one TCP path worked at that time. It does not test the HTTPS response, certificate, bandwidth or your own device latency. If different regions resolve different addresses, compare the addresses before attributing the timing difference to geography. Reserved `.example` Break it fixtures run locally and illustrate refusal, silence and partial success. They are not evidence about a live server. Re-enter the live target and press Ping for a new measurement after changing configuration. ## For agents The Tamperbox MCP server runs the same measurement. Search its catalog for `tcp_ping`, inspect the input schema, and call it with a host, a port and optionally the regions. Each call spends one probe per region. Keep these warnings with any conclusion: - A timeout is inconclusive; only a refusal is a definite "nothing listening". - Only the first resolved address was tested. - A connected handshake does not prove the application works. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/), and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the input travels. [ASN Lookup](https://docs.tamperbox.dev/tools/asn-lookup/) names the network that announces the address. ### Transfers to another tool Explicit sibling-tool controls can carry the current input or observed address to another page. The shared navigation stores that value temporarily in tab-scoped `sessionStorage`, accepts a transfer for at most one minute, and puts a random transfer token in the URL fragment. The input itself is not placed in the URL. The receiving page consumes the transfer and applies its own input rules; tools with a manual Run button still require that action for live checks. This is not a saved result, and the destination can send the value to the services it needs. Ordinary edits and lookups do not create a durable report archive. ## Limits - Three broad regions, three attempts each, at one moment. - One address per test; other addresses are listed, not tested. - TCP only: UDP services (most voice, many game servers, QUIC) cannot be tested. - Names that resolve to private or reserved addresses are refused. - Sample results under `.example` are fixed and labelled. - The page keeps results in memory. Explicit transfers to another tool use temporary session storage. ## References - [RFC 9293](https://www.rfc-editor.org/rfc/rfc9293), Transmission Control Protocol: sections 3.5, 3.5.2 and 3.5.3. Obsoletes [RFC 793](https://www.rfc-editor.org/rfc/rfc793). - [RFC 792](https://www.rfc-editor.org/rfc/rfc792), Internet Control Message Protocol: the Echo and Destination Unreachable messages. - [RFC 8305](https://www.rfc-editor.org/rfc/rfc8305), Happy Eyeballs Version 2: sections 4 and 5. - [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3), [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598#section-4), [RFC 4193](https://www.rfc-editor.org/rfc/rfc4193#section-3): private, shared and unique local address space. - [RFC 5737](https://www.rfc-editor.org/rfc/rfc5737#section-3), [RFC 3849](https://www.rfc-editor.org/rfc/rfc3849#section-2): documentation addresses. --- # Tool pages Each Tamperbox tool page opens on a live result or controlled example, shows its verdict and evidence, and links here for the method behind every finding. Canonical: https://docs.tamperbox.dev/tools/ Updated: 2026-10-19 Applies to: tamperbox.dev, October 2026 Outputs: The documentation page for a Tamperbox tool, with its method, finding reference and guide Limitations: Only the tools listed here have a documentation page; the other tool pages carry their full reference on the page itself. A tool page on [tamperbox.dev](https://tamperbox.dev) has one job: take one input, show the verdict, and show the evidence behind it. The page keeps a short "How it works", the limits that change how you read a result, three questions people ask, and the standards it follows. Everything longer lives here. Each tool's documentation has the same shape, so a finding on the page always has a place to point to: | Section | What it holds | Where the page links to it | | --- | --- | --- | | Method | Every rule the tool applies, in the order it applies them, with the exact wording of each finding | "Read the method" on the What does it mean and Tool limitations cards | | Finding reference | One row per finding: severity, what it means for whoever receives the output, the fix | The finding itself | | Guide | Step by step, for each situation the tool can put you in, including how to verify the fix | "Step by step on docs" on the How to fix it card | | Worked example | The live default or an explicitly loaded controlled sample, read end to end, and what each Break it case shows | "Worked examples on docs" | | For agents | How to run the same check through the MCP server and what the result does not prove | The For agents band on the page | <div class="tb-doc-grid"> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/dns-lookup/"><strong>DNS Lookup</strong><span>Any record type from a public resolver or the zone itself, with status, flags and the DNSSEC answer bit.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/txt-lookup/"><strong>TXT Record Lookup</strong><span>Every TXT record on a name, named by what it is for, with its strings measured against the 255-character limit.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/cname-lookup/"><strong>CNAME Lookup</strong><span>The alias chain from a name to its address, with dangling targets, apex aliases and loops caught.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/ns-lookup/"><strong>NS Lookup</strong><span>The nameservers a zone delegates to, the provider behind each, and the unfinished migration.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/soa-lookup/"><strong>SOA Lookup</strong><span>A zone’s SOA field by field, the serial read as a date, and the four timers checked.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/aaaa-lookup/"><strong>AAAA Lookup</strong><span>A name’s IPv6 addresses, sorted by kind, with the network behind each and the IPv4 question answered.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/srv-lookup/"><strong>SRV Lookup</strong><span>The servers a service names, in priority order, with each one’s share of connections.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/caa-lookup/"><strong>CAA Lookup</strong><span>Which certificate authorities may issue for a name, inherited from parents, against the certificates already logged.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/dns-propagation/"><strong>DNS Propagation Checker</strong><span>Twelve public resolvers against the zone’s own answer, with the cache time left on every old answer.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/json-to-yaml/"><strong>JSON to YAML Converter</strong><span>Convert locally, reject duplicate keys and unsafe integers, and verify the resulting data.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/yaml-to-json/"><strong>YAML to JSON Converter</strong><span>Resolve compatible YAML values, inspect presentation loss, and test aliases and numeric limits.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/cdn-detector/"><strong>CDN Detector</strong><span>How Tamperbox combines DNS, network and HTTPS response clues to identify a likely content delivery network.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/dns-provider/"><strong>DNS Provider Lookup</strong><span>How Tamperbox groups authoritative nameservers, recognises providers, and flags fragile or mixed delegation.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/domain-health/"><strong>Domain Health Check</strong><span>How Tamperbox combines DNS, mail, TLS, HTTP and security-header observations into one bounded health report.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/website-hosting/"><strong>Website Hosting Checker</strong><span>How Tamperbox follows website DNS, maps public addresses to networks, and compares the apex with www.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/website-technology/"><strong>Website Technology Detector</strong><span>How Tamperbox identifies web technologies from bounded HTML and response-header signatures without executing the page.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/saas-stack/"><strong>SaaS Stack Detector</strong><span>How Tamperbox reads public TXT records for service-verification tokens and SPF senders without claiming that an account is active.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/subdomain-finder/"><strong>Subdomain Finder</strong><span>How Tamperbox extracts DNS names from public Certificate Transparency observations and labels risky-looking names.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/email-domain/"><strong>MX Lookup & Email Domain Checker</strong><span>How Tamperbox validates a mail domain, reads MX and address fallback records, identifies null MX, and explains what public routing evidence proves.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/email-provider/"><strong>Email Provider Lookup</strong><span>How Tamperbox attributes public MX hostnames to mailbox services and gateways, handles mixed routes, and preserves uncertainty about the downstream mailbox host.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/ssl-checker/"><strong>SSL Certificate Checker</strong><span>The certificate a server really sends, its chain on one time axis, the names it covers, the connection it negotiated.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/dane-checker/"><strong>DANE & TLSA Checker</strong><span>The TLSA records of every mail server, whether DNSSEC protects them, and which one matches the certificate the server presents.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/security-headers/"><strong>Security Headers Checker</strong><span>The six headers a response sends to protect visitors, the rule behind each point of the grade, and the lines to send instead.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/security-txt-checker/"><strong>security.txt Checker</strong><span>A site's security.txt read the way a researcher reads it, checked against RFC 9116, with a corrected file to publish.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/post-quantum-checker/"><strong>Post-Quantum TLS Checker</strong><span>Two handshakes on port 443: the key exchange group a server chooses, and whether it takes ML-KEM when nothing else is offered.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/dkim-checker/"><strong>DKIM Record Checker</strong><span>Every DKIM key a domain publishes, measured from the key bytes, with the selector found for you.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/spf-checker/"><strong>SPF Checker</strong><span>Every DNS lookup an SPF record costs, the include tree behind it, and a flattening plan that replaces only what it must.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/dmarc-checker/"><strong>DMARC Checker & Generator</strong><span>The policy graded tag by tag, and the next record on the path from p=none to reject, with every change kept in History.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/mta-sts-checker/"><strong>MTA-STS & TLS-RPT Checker</strong><span>The chain a sending server follows: the record, the policy file, MX coverage and TLS reports, with a policy that covers every server.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/bimi-checker/"><strong>BIMI Record Checker</strong><span>The record, the SVG logo, the mark certificate and the DMARC policy behind a logo in the inbox.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/email-header-analyzer/"><strong>Email Header Analyzer</strong><span>A message's route hop by hop, the receiver's authentication results, and the identities compared, all in the browser.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/redirect-checker/"><strong>Redirect Checker</strong><span>Every hop of a redirect chain with what changed on each, and the loops, downgrades and temporary codes to fix.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/http3-checker/"><strong>HTTP/3 & Compression Checker</strong><span>The HTTP/3 offer and a QUIC connection, what each Accept-Encoding gets back, and HSTS against the preload list's rules.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/cors-tester/"><strong>CORS Tester</strong><span>The browser's CORS algorithm step by step, from the preflight to the real response, with the headers that would allow the request.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/jwt/"><strong>JWT Decoder & Verifier</strong><span>A token's header and claims decoded in the browser, its signature verified with your key, and test tokens rebuilt from edited claims.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/unix-timestamp/"><strong>Unix Timestamp Converter</strong><span>One instant in every format, the unit and zone it was read in, and what happens at 2038, before 1970 and across a clock change.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/hidden-characters/"><strong>Hidden Character Checker</strong><span>Zero width, direction and look-alike characters found, the text counted four ways, and cleaned.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/naughty-strings/"><strong>Naughty Strings List</strong><span>Hostile test strings that say what they test, with active payloads kept apart.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/string-length-generator/"><strong>Exact-Length String Generator</strong><span>Strings of an exact size in characters, UTF-16 units or bytes, limit sets and counterstrings.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/mojibake-fixer/"><strong>Mojibake Fixer</strong><span>Garbled UTF-8 repaired run by run, and what was lost for good.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/har-sanitizer/"><strong>HAR File Sanitizer</strong><span>Secrets and personal values replaced with stable placeholders, and the failed requests listed for a ticket.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/postman-converter/"><strong>Postman Collection Converter</strong><span>Postman, OpenAPI and cURL converted in the browser, with a report of what was kept, dropped and redacted.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/mixed-content-checker/"><strong>Mixed Content & Cookie Checker</strong><span>Every http:// address on an HTTPS page sorted by what browsers do with it, and every cookie judged against the rules browsers enforce.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/dnssec-checker/"><strong>DNSSEC Checker</strong><span>Resolver validation and the diagnostic chain of DS, keys and signature windows.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/reverse-dns/"><strong>Reverse DNS Lookup</strong><span>PTR names and forward confirmation for a domain or IP addresses.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/domain-availability/"><strong>Domain Availability Checker</strong><span>Registration evidence, dates and status codes without a guarantee of availability.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/whois-lookup/"><strong>WHOIS & RDAP Lookup</strong><span>Domain and network registry records, contacts and raw RDAP evidence.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/asn-lookup/"><strong>ASN Lookup</strong><span>Routing origins, registry allocation holders and their evidence limits.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/bgp-lookup/"><strong>BGP Route Lookup</strong><span>Collector visibility, route objects and reported routing incidents.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/tcp-ping/"><strong>TCP Ping</strong><span>TCP connect times and individual attempts from selected regions.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/minecraft-server-status/"><strong>Minecraft Server Status Checker</strong><span>Java Edition status replies, SRV selection and player-report limits.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/open-port-checker/"><strong>Open Port Checker</strong><span>A TCP check of the request-source address and port-forward troubleshooting.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/what-is-my-ip/"><strong>What Is My IP Address?</strong><span>The observed public address and optional browser IPv4/IPv6 tests.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/connection-info/"><strong>My Connection Info</strong><span>TLS, HTTP and round-trip metadata for the connection to the edge.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/website-down-checker/"><strong>Website Down Checker</strong><span>One request from our server: up, slow, erroring or down, and the stage where a request stopped.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/broken-link-checker/"><strong>Broken Link Checker</strong><span>Every link, image and script on one page requested from our server: broken, unclear, redirected or working, with where each one sits.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/open-graph-preview/"><strong>Open Graph Preview</strong><span>The card every platform draws for a link, from its Open Graph, X and HTML tags, with the tags to add.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/robots-txt-checker/"><strong>Robots.txt & Sitemap Checker</strong><span>Which search and AI crawlers the rules let in, the line that decides any URL, and the sitemaps they announce.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/ads-txt-checker/"><strong>Ads.txt & App-Ads.txt Checker</strong><span>Every ads.txt line buyers would skip, and each seller checked against its ad system's sellers.json.</span></a> <a class="tb-doc-card" href="https://docs.tamperbox.dev/tools/llms-txt/"><strong>llms.txt Checker & Generator</strong><span>The outline an AI agent reads from a site's llms.txt, every format problem, and a draft made from the site itself.</span></a> </div> ## Where processing happens Every tool page says, next to its verdict, where your input goes. The rule is the same across tools: - **Pasted evidence is parsed locally when the tool supports that mode.** A pasted domain still starts a live lookup. Website Hosting Checker also looks up network information for pasted public IP addresses. Read the tool’s processing notice before running it. - **A host name or domain means a named server-side check.** The server makes the required connection, DNS queries or published-file fetches, returns what it saw, and keeps nothing. The page names the port and the records or files it checks before it runs them. Explicit sibling-tool links temporarily use browser session storage and a random transfer token in the URL fragment. The transferred input itself is not placed in the URL. See each guide for its input handling and network requests. ## Break it, Heal it, History Tool pages offer Break it examples and applicable Heal it repairs. Pages with History also expose Revert and Reset input: - **Break it** loads a deliberate edge case built from your own input where that is possible, so you see what the finding looks like before it happens to you. - **Heal it** offers the repairs the tool found, each saying what it will change. After a break with no repair, it offers to restore the input you had before. - **History**, under the result, logs every change with what it replaced. Revert undoes the newest change; Reset input returns to what you entered. --- # TXT Record Lookup How the TXT Record Lookup reads every TXT record at a name, names what each one is for, measures the strings it is split into, flags duplicate SPF records and over-long strings, and how to fix and confirm each one. Canonical: https://docs.tamperbox.dev/tools/txt-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A DNS name, or TXT records to paste (a dig answer, zone file lines or bare values) Outputs: A verdict naming the records found, findings, one row per record with its kind, length and string count, and the answer as dig-style text Limitations: Records are named from their prefix, not evaluated; SPF and DMARC policies are checked by their own tools; records at prefixed names such as _dmarc need that full name The tool page is [tamperbox.dev/txt-lookup](https://tamperbox.dev/txt-lookup). It opens on `harbor-supply.example`, a sample domain on the reserved `.example` zone, answered in the browser: an SPF record, seven verification tokens and one value the tool does not recognise. This page is the long version: how records are read and named, the two rules the tool enforces, and how to publish a TXT record that receivers read the way you wrote it. <div class="tb-callout"><strong>Where processing happens:</strong> a name is sent to the Tamperbox server, which asks Cloudflare for its TXT records over DNS over HTTPS and returns them. Pasted records are parsed in your browser and never uploaded. Sample names under <code>.example</code> are answered in the browser. Ordinary lookup results are not persisted by this page. An explicit handoff temporarily stores its value in session storage for one-use transfer.</div> ## What the tool answers A TXT record is free text attached to a name ([RFC 1035 section 3.3.14](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.14)): "the semantics of the text depends on the domain where it is found." In practice almost every TXT record is read by one machine for one purpose. The tool answers: 1. **What does this name publish?** Every TXT record, in full. 2. **What is each record for?** SPF, DMARC, a DKIM key, MTA-STS, TLS reporting, BIMI, a verification token for a known service, or something else. 3. **Is any value split wrongly?** How long each value is, how many strings it is stored in, and whether any one string is over the 255-character limit. 4. **Is there more than one SPF record?** The one structural mistake in TXT data that breaks mail for a whole domain. It does not evaluate an SPF or DMARC policy, does not prove that a verification token is still in use, and does not look below the name you give: a DMARC record lives at `_dmarc.<domain>` and a DKIM key at `<selector>._domainkey.<domain>`, so the apex does not show them. ## Inputs ### A name `example.com`, `_dmarc.example.com`, `selector1._domainkey.example.com`. The lookup runs when you stop typing, or at once on Enter. The name is validated in the browser and on the server (at most 253 characters, labels of letters, digits, hyphens and underscores). A pasted web address or email address is reduced to its host or domain, and the hint names what was kept; text that does not reduce stays as pasted. ### Pasted records Anything with a space or a quote in it is read as records, in the browser. Three shapes are accepted: - a dig answer: `example.com. 300 IN TXT "v=spf1 -all"`; - zone file lines, with the class and TTL in either order; - bare values, one per line, which are taken as TXT data with no owner name. Comments after a `;` outside quotes are dropped. The page cannot know whether DNS serves pasted records today; the verdict says "Read from the pasted records." ### Files Drop a `.txt` file anywhere on the page. It is read in the browser. ## Reading the result ### Verdict and chips "9 TXT records at example.com: SPF, 7 verification tokens, 1 other." when nothing is wrong; the first failure otherwise, for example "2 SPF records:". The line under it says who answered. The chips count the records and, when there are any, the problems. ### Where your input goes Pasted records stay in the browser; a name means one TXT query from our server. Both are true for every input. ### Findings The failures, worst first, or one pass saying how many records were read. ### TXT records One row per record: its kind as a tag, its length in characters, how many strings it is stored in, and the joined value. A row with an over-long string is marked as failing. ### DNS response The answer as dig-style text, with a copy button. ### History and Heal it History logs every Break it and Heal it change. For pasted records with an over-long string, Heal it splits every value into quoted strings of 255 characters or fewer. ### Take it further The owner name of each recognised record is handed to the specialist for a fresh lookup: the SPF owner to the SPF Checker, a DMARC record (or a domain that publishes SPF) to the DMARC Checker, a DKIM key at its full name to the DKIM Checker, an MTA-STS record to the MTA-STS Checker, a BIMI record to the BIMI Checker. Each opens the other tool with the value in its box; the input stays out of the URL; a temporary random fragment identifies a one-use transfer held in session storage. ## Method ### 1. Reading the strings A TXT record holds one or more character-strings. [RFC 1035 section 3.3](https://www.rfc-editor.org/rfc/rfc1035#section-3.3) defines one as "a single length octet followed by that number of characters", up to 256 octets including the length octet: 255 characters of text. Resolvers and our server print each string in double quotes, so the page reads every quoted string, unescapes nothing it does not need to, and joins them with no separator to get the record's value. That matches [RFC 7208 section 3.3](https://www.rfc-editor.org/rfc/rfc7208#section-3.3): the strings "MUST be treated as if those strings are concatenated together without adding spaces." A record with no quotes is taken as one value. ### 2. Naming each record The joined value is compared with these prefixes, in order; the first match names the record. | Kind | Rule | Where the record should live | | --- | --- | --- | | SPF | starts with `v=spf1`, case-insensitive, followed by a word break | the domain that sends, [RFC 7208 section 4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | | DMARC | starts with `v=DMARC1` | `_dmarc.<domain>`, [RFC 7489 section 6.1](https://www.rfc-editor.org/rfc/rfc7489#section-6.1) | | DKIM key | starts with `v=DKIM1`, or carries a `p=` of 40 or more base64 characters | `<selector>._domainkey.<domain>`, [RFC 6376 section 3.6.2.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.2.1) | | MTA-STS | starts with `v=STSv1` | `_mta-sts.<domain>`, [RFC 8461 section 3.1](https://www.rfc-editor.org/rfc/rfc8461#section-3.1) | | TLS reporting | starts with `v=TLSRPTv1` | `_smtp._tls.<domain>`, [RFC 8460 section 3](https://www.rfc-editor.org/rfc/rfc8460#section-3) | | BIMI | starts with `v=BIMI1` | `<selector>._bimi.<domain>` | | Service verification | starts with one of 35 catalogued prefixes, for example `google-site-verification=`, `MS=ms`, `facebook-domain-verification=`, `apple-domain-verification=` | the name the service asked for, usually the apex | | Other | anything else | | The verdict counts the kinds, puts the tokens together as "N verification tokens", and counts the rest as "other". A verification token says only that someone once proved control of the domain to that service; it does not prove a current account. ### 3. Rule: one SPF record per name [RFC 7208 section 3.2](https://www.rfc-editor.org/rfc/rfc7208#section-3.2): "A domain name MUST NOT have multiple records that would cause an authorization check to select more than one record." And [section 4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5): "If the resultant record set includes more than one record, check_host() produces the "permerror" result." Two or more records named SPF on this page give a fail, "N SPF records". Every receiver that evaluates SPF for the domain gets permerror instead of a pass or fail, so SPF cannot contribute a pass to DMARC; mail then depends on an aligned DKIM signature. ### 4. Rule: no character-string over 255 characters Any quoted string longer than 255 characters gives a fail, "A KIND string is N characters". A DNS server cannot store it as one string, so a provider's control panel either refuses it, cuts it, or splits it on its own; the record receivers read is then not the one you wrote. The fix is to split the value into several quoted strings in the same record, which receivers join back together (step 1). The tool does not limit the total length of a record: long DKIM keys are normally stored as two or three strings. ### What the tool does not judge The content of a record is not evaluated: an SPF record with eleven lookups or a DMARC record with a typo pass here. [RFC 7208 section 3.4](https://www.rfc-editor.org/rfc/rfc7208#section-3.4) also asks that an SPF answer stay small enough to fit in 512 octets; the page shows lengths but does not apply that limit. Use the [SPF Checker](https://tamperbox.dev/spf-checker) and the [DMARC Checker](https://tamperbox.dev/dmarc-checker) for the content. ## Standards and conformance | Specification | Sections used | How the tool applies it | Where it stops | | --- | --- | --- | --- | | [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035) | [3.3](https://www.rfc-editor.org/rfc/rfc1035#section-3.3), [3.3.14](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.14) | Each quoted string is measured against the 255-character limit; strings are joined for the value | Escapes inside strings are shown as the server prints them | | [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208) | [3.2](https://www.rfc-editor.org/rfc/rfc7208#section-3.2), [3.3](https://www.rfc-editor.org/rfc/rfc7208#section-3.3), [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | More than one SPF record is a fail; strings are joined without spaces | SPF is detected with a word break after `v=spf1`, slightly more lenient than the "space or end" the RFC requires; terms are not evaluated | | [RFC 7489](https://www.rfc-editor.org/rfc/rfc7489) | [6.1](https://www.rfc-editor.org/rfc/rfc7489#section-6.1) | A `v=DMARC1` value is named DMARC and handed to the DMARC Checker | Tags are not parsed here | | [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376) | [3.6.2.1](https://www.rfc-editor.org/rfc/rfc6376#section-3.6.2.1) | A key at `<selector>._domainkey` is handed to the DKIM Checker | Keys are not decoded here | | [RFC 8461](https://www.rfc-editor.org/rfc/rfc8461) and [RFC 8460](https://www.rfc-editor.org/rfc/rfc8460) | [3.1](https://www.rfc-editor.org/rfc/rfc8461#section-3.1), [3](https://www.rfc-editor.org/rfc/rfc8460#section-3) | `v=STSv1` and `v=TLSRPTv1` values are named | The policy file and report addresses are checked by the MTA-STS Checker | ## Finding reference | Finding | Severity | Source | What it means for receivers | Fix | | --- | --- | --- | --- | --- | | N TXT records read | pass | [RFC 1035 3.3.14](https://www.rfc-editor.org/rfc/rfc1035#section-3.3.14) | Every record is well formed | None | | N SPF records | fail | [RFC 7208 3.2](https://www.rfc-editor.org/rfc/rfc7208#section-3.2), [4.5](https://www.rfc-editor.org/rfc/rfc7208#section-4.5) | SPF returns permerror for every message from the domain | Merge into one record | | A KIND string is N characters | fail | [RFC 1035 3.3](https://www.rfc-editor.org/rfc/rfc1035#section-3.3) | The record receivers read differs from the one you wrote, or was refused | Split into strings of 255 characters or fewer | | No TXT record at name | info | [RFC 2308 2.2](https://www.rfc-editor.org/rfc/rfc2308#section-2.2) | Nothing to read here; a service looking for its token finds none | Publish at the exact name the service gave | | The name does not exist | fail | [RFC 2308 2.1](https://www.rfc-editor.org/rfc/rfc2308#section-2.1) | No record of any type at this name | Check the name; add the record | | The resolver could not answer | fail | [RFC 1035 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1) | Validating resolvers return nothing for the name | Check the zone's DNSSEC chain | ## Guide ### Two SPF records Usually a second service told you to "add this TXT record" and you did, next to the one you had. Merge them: keep one `v=spf1` record with every `include:`, `ip4:` and `ip6:` term from both and one `all` at the end, then delete the other. Paste both into the [SPF Checker](https://tamperbox.dev/spf-checker), which merges them and counts the DNS lookups the result costs. Confirm with `dig +short TXT example.com`: exactly one line starts with `"v=spf1`. ### A string over 255 characters Most providers split long values for you when you paste them whole; a few store them as typed and fail later. Write the record as quoted pieces of at most 255 characters each, side by side in one record: ```text example.com. 3600 IN TXT "v=spf1 include:_spf.google.com include:mailgun.org ... " "include:sendgrid.net -all" ``` Then look the name up here: the record shows "in 2 strings" and no failure. `dig +short TXT example.com` prints the pieces in quotes; that is how it should look. ### A verification token the service cannot find Tokens live where the service says, often the apex, sometimes a prefixed name such as `_github-challenge-<org>.example.com`. Look that exact name up here. If the token is there and the service still fails, the record may have been added minutes ago: resolvers cache an empty answer for the zone's negative TTL (the last field of its SOA). ### Records that live at prefixed names A DMARC record is at `_dmarc.example.com`, a DKIM key at `selector1._domainkey.example.com`, MTA-STS at `_mta-sts.example.com`. The Break it case "The DMARC name" looks up the DMARC name of your domain. ### Break it cases | Case | What it loads | What it shows | | --- | --- | --- | | One string too long | your SPF record, pasted back as one string over 255 characters | The length failure, and Heal it splitting the string | | Two SPF records | your records plus a second SPF record | "2 SPF records" | | The DMARC name | `_dmarc.` plus your registrable domain | The DMARC record, handed on to the DMARC Checker | | No TXT records | `nohost.` in front of your name | A name that does not exist | ## Worked example `harbor-supply.example` publishes nine TXT records: one SPF record that includes four sending services and one address, seven verification tokens for services the catalogue knows (two for Google, then Microsoft 365, Atlassian, Stripe, DocuSign and Meta), and one token for a service it does not, shown as Other. The verdict reads "9 TXT records at harbor-supply.example: SPF, 7 verification tokens, 1 other." with "The sample zone answered." under it, since no resolver was asked. There is nothing to fix; Take it further offers the SPF owner name to the SPF Checker and the domain to the DMARC Checker, both of which answer the sample in the browser too. Press "Two SPF records" and the page loads the same nine records plus a second SPF record, as pasted text: the verdict turns to "2 SPF records:" and the cards explain permerror. Press "One string too long" and the SPF record comes back as one string of more than 255 characters; Heal it splits it, and Revert brings the break back. ## For agents The Tamperbox MCP server exposes `txt_lookup` with a `name`. It returns an `evidence` object containing the question, status, flags, answer and authority, plus `records` for the requested type, with each record's text as the resolver returned it. Keep these warnings with any conclusion: - A verification string does not prove a current service account. - The record's kind comes from its prefix; SPF and DMARC content is not evaluated (use the SPF and DMARC operations). - One answer from one resolver at one moment. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/). ## Limits The DNS wire limit is 255 octets per character-string. The current page measures JavaScript string length and splits pasted text into 255-character pieces; for non-ASCII text or escape sequences this is not a wire-byte validator. Confirm the encoded record with your DNS provider. - Kinds come from prefixes and a catalogue of 35 token formats; an unknown token shows as Other. - No policy evaluation: an SPF record that would fail evaluation still passes here. - Records at prefixed names are found only when you ask for that name. - Pasted records are read as text; the page cannot say whether DNS serves them. - Sample names under `.example` are answered in the browser. ## References - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035): sections 3.3 (character-strings) and 3.3.14 (TXT RDATA). - [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208): SPF. Sections 3.2 (multiple records), 3.3 (multiple strings), 3.4 (record size), 4.5 (selecting records). - [RFC 7489](https://www.rfc-editor.org/rfc/rfc7489): DMARC. Section 6.1, the `_dmarc` name. - [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376): DKIM. Section 3.6.2.1, the `_domainkey` namespace. - [RFC 8461](https://www.rfc-editor.org/rfc/rfc8461): MTA-STS. Section 3.1, the `_mta-sts` record. - [RFC 8460](https://www.rfc-editor.org/rfc/rfc8460): SMTP TLS reporting. Section 3, the `_smtp._tls` record. - [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308): negative caching. Sections 2.1 and 2.2. --- # Unix Timestamp Converter How the converter reads an epoch number, an ISO date or an HTTP date in the browser, every rule behind its verdict, what each finding means, and how to confirm a conversion outside Tamperbox. Canonical: https://docs.tamperbox.dev/tools/unix-timestamp/ Updated: 2026-10-21 Applies to: tamperbox.dev, October 2026 Prerequisites: An epoch number, an ISO 8601 date or date-time, or an HTTP date to paste, one per line for a batch Outputs: A verdict with Pass and Check chips, the instant in every format, calendar facts, shift and snap targets, line-by-line batch output and a code snippet per language Limitations: A unit guessed from the digit count is a hint, not a fact; time zone rules come from the browser's own database; instants are limited to the years 0001 to 9999; nothing is sent anywhere The tool page is [tamperbox.dev/unix-timestamp](https://tamperbox.dev/unix-timestamp). It opens on a reserved sample value, `1760000000`, answers in one sentence what instant that is and how sure it can be, and shows the same instant in every format under it. This page is the long version: what the page does to your input before reading it, every rule behind the verdict, what each finding means, and how to confirm a conversion with tools you already have. <div class="tb-callout"><strong>Where processing happens:</strong> everything runs in your browser. Values, time zones and templates are parsed and formatted locally and never uploaded. The only thing that leaves the page is the value you choose to send to the JWT page, and that travels through same-site tab memory, never through a URL or browser storage. Nothing is stored.</div> ## What the tool answers Four questions, in the order the page settles them: 1. **What instant is this?** The value read as one exact point in time, to the nanosecond, shown as a readable date and in every common format. 2. **How sure is that reading?** Whether the unit was chosen or guessed from the digit count, and whether a date without an offset was read in a time zone you chose. 3. **Will it survive the systems it passes through?** Whether the seconds fit a signed 32-bit integer, and what each language or database keeps of the precision. 4. **What happens at the edges?** The epoch itself, dates before 1970, a skipped or repeated hour at a clock change, a day that does not exist. The verdict names the worst of these. The chips repeat the two that matter most: how the value was read, and the 32-bit range. Findings under the verdict list the rest, worst first; a batch reports how many lines converted. ## Inputs The field takes one value, or one value per line. Every value is trimmed. A value longer than 500 characters, or an input longer than 20,000 characters or 200 non-empty lines, is refused with the limit named. Blank lines are ignored. Pasting anywhere on the page replaces the input; typing never triggers a repair. ### An epoch number A plain decimal number with an optional sign and fraction: `1760000000`, `-1`, `1700000000.123456789`. Separators, exponent notation and an integer part over 30 digits are refused. In **Auto** mode the unit comes from the number of digits before the decimal point, ignoring the sign and leading zeros: | Digits | Unit read | Example | | --- | --- | --- | | up to 11 | seconds | `1760000000` | | 12 to 14 | milliseconds | `1760000000000` | | 15 to 17 | microseconds | `1760000000000000` | | 18 or more | nanoseconds | `1760000000123456789` | A unit you select in **Read the number as** always wins. The list shows the date the same digits give in each unit, so a wrong guess is visible where it is corrected. A fraction may carry at most the digits that unit has below the nanosecond: nine for seconds, six for milliseconds, three for microseconds, none for nanoseconds. Non-zero digits beyond that are refused rather than rounded. ### An ISO 8601 date or date-time `YYYY-MM-DD`, optionally followed by `T`, `t` or a space, then `HH:mm`, optional `:ss`, up to nine fractional digits, and `Z`, `z`, `+HH:MM` or `+HHMM`. A date alone means midnight. A value with `Z` or an offset is absolute. A value without one is read in the input time zone, UTC by default, and the verdict says so. The exact shape is the [RFC 3339 §5.6](https://www.rfc-editor.org/rfc/rfc3339#section-5.6) `date-time` grammar, with the space separator that section permits and seconds made optional. ### An HTTP date Exactly the IMF-fixdate shape of [RFC 9110 §5.6.7](https://www.rfc-editor.org/rfc/rfc9110#section-5.6.7): `Thu, 09 Oct 2025 08:53:20 GMT`. The weekday must match the date. The two obsolete forms (RFC 850 and asctime) are not read from the input field, but they can be edited in their own result rows. ### Reading options - **Read the number as**: Auto, seconds, milliseconds, microseconds or nanoseconds. Shown when a line is a number. - **Read the time in**: an IANA zone name from your browser's list. Shown when a value has no offset. An unknown name stops the whole input with "Choose a valid IANA time zone, such as America/New_York." - **Earlier / Later**: shown when a local time happens twice. ### What Heal it cleans Repairs appear for a single value only, each with the reading it would produce, and nothing changes until you apply one: | Repair | When | What it does | | --- | --- | --- | | Clean pasted value | Quotes, curly quotes, a Unicode minus, comma groups (`1,700,000,000`) or underscore groups (`1_700_000_000`) wrap a value that converts once removed | Removes the wrappers; the digits are unchanged | | Read unit suffix | The value ends in `s`, `ms`, `us`, `µs` or `ns` | Sets the unit from the suffix | | Interpret as … | The selected unit disagrees with the digit count, or the value is out of range in the selected unit | Changes the unit, showing the date each reading gives | | Use HH:MM, before or after the jump | The local time falls in a skipped hour | Rewrites the value with the offset from either side | | Make UTC or the offset explicit | The value had no offset | Writes the same instant with its offset | ## Reading the result ### Verdict and chips One sentence, then the note that explains it. The first chip says how the value was read: **Unit guessed from 10 digits** or **No offset, read in UTC** (Check), or **Unit set to seconds** or **Offset in the input** (Pass). The second says **Fits signed 32-bit seconds** (Pass) or **Outside the signed 32-bit seconds range** (Check). A value that failed gets a chip that leads to the fix: **Choose earlier or later**, **n repairs in Heal it**, or **Edit the input**. ### Findings Under the verdict, worst first: the guessed unit, the assumed zone, the 32-bit range and the negative or epoch-zero notices. Passes fold into one line. ### Every format One row per format family. ISO and HTTP rows are always UTC; the time zone row, SQL and the custom template follow the display zone. Each row has a picker for its variant (ISO with milliseconds, RFC 3339 with a space, ISO week or ordinal date, RFC 5322, RFC 850, C asctime, SQL with offset) and a Copy button. Rows are editable: a changed value is read back in that row's own strict shape, Enter applies and Esc restores, and the weekday of an HTTP or email date follows the date you type. ### Adjust this instant **Shift** moves by an exact elapsed amount in seconds, minutes, hours, days of 24 hours or weeks of 7 × 24 hours, independent of clock changes. **Snap** moves to the start or end of the day, week, month or year in the display zone; weeks start on Monday and an end is one nanosecond before the next period. **Now** loads the device clock in milliseconds. Every target is shown before it is applied. ### Compare with another instant A second timestamp or date, read with the same unit, input zone and repeated-time choice as the main value. The result states the difference between the two instants; neither value leaves the page. ### Line by line For several lines, each converts on its own with the same unit and zone. Failed lines keep their position and read `Line N: ERROR:` with the reason. **Copy all as** takes a format and zone; **Use as input** replaces the input with the converted lines when every line converted and the format can be read back. ### Use in code The instant rebuilt in 14 languages and databases, each note saying what precision the target type keeps. ### History History sits below the complete conversion result. Every Break it, Heal it, shift, snap and Now action is logged with what it replaced, newest first, up to 50 entries. **Revert** undoes the newest; **Reset input** returns to what you entered and clears the log. Input, unit, time zone and the DST choice are all recorded. ### Take it further **Use as JWT expiry** opens the JWT page in a new tab with an unsigned test token whose `exp` is this instant rounded down to whole seconds. The value moves through same-site tab memory only. The token is a fixture, never a credential: its header is `alg: none`. ## Method The rules, in the order the page applies them. Finding wording is quoted from the code. ### Rule 1: the shape of the value A trimmed value is tried as an epoch number, then as an HTTP date, then as an ISO date. Anything else fails with "Use an epoch number, YYYY-MM-DD, ISO date-time, or an HTTP date ending in GMT. Ambiguous date orders are not guessed." The verdict reads **Not a format this tool reads.** Slash dates such as `03/04/2024`, natural language and `1.7e9` fall here on purpose: no guess is safer than a wrong one. ### Rule 2: unit and precision With Auto, the unit follows the digit table above and the note reads "Assumed seconds from digit count. Override the input unit if needed." The verdict is **One instant, assuming seconds.** and the chip a Check. Digits finer than the nanosecond fail with "Precision beyond nanoseconds cannot be represented." (verdict **Finer than nanoseconds.**). All arithmetic is on integer nanoseconds; a `Date` is created only after the nanoseconds are split off, so no precision is lost to floating point. ### Rule 3: the supported range Instants must fall from `0001-01-01T00:00:00Z` to the end of 9999, judged on the millisecond. Outside it: "Supported dates run from year 0001 through 9999." (verdict **Outside years 0001 to 9999.**). The limit is the page's own choice for consistent ISO and Intl output, narrower than the ±8.64 × 10¹⁵ ms a JavaScript `Date` can hold ([ECMA-262, time values and time range](https://tc39.es/ecma262/#sec-time-values-and-time-range)). A millisecond value read as seconds lands tens of thousands of years ahead and fails here, which is why the range error offers **Interpret as milliseconds**. ### Rule 4: calendar validity Month 1 to 12, a real day of that month, hour to 23, minutes and seconds to 59. `2023-02-29`, `2024-04-31` and a `:60` leap second fail with "Invalid calendar date or time. Leap seconds and rolled-over dates are not accepted." (verdict **Not a real calendar date.**). Unix time has no leap seconds: [POSIX §4.16](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16) defines seconds since the Epoch as "a value that approximates the number of seconds that have elapsed since the Epoch", by a formula in which every day has 86,400 seconds. An HTTP date whose weekday does not match fails with "The HTTP date or weekday is invalid." ### Rule 5: offsets and zones An offset `[+-]HH:MM` or `[+-]HHMM` is applied as written; hours over 23 or minutes over 59 fail with "Invalid UTC offset." `-00:00`, the unknown-local-offset convention of [RFC 3339 §4.3](https://www.rfc-editor.org/rfc/rfc3339#section-4.3), is read as UTC. Without an offset, the civil time is resolved in the input zone by sampling the zone's offsets around it, so transitions that are not on the hour and skipped dates are found. The note reads "No offset in input: interpreted in Europe/Berlin." and the verdict **One instant, assuming Europe/Berlin time.** - A time inside a forward clock change fails: "This local time does not exist in that zone (a clock change skipped it). Enter an explicit UTC offset or choose another time." (verdict **Not a real time in America/New_York.**). - A time repeated by a backward change fails until you choose: "This local time occurs twice. Choose the earlier or later occurrence, or enter an explicit UTC offset." (verdict **This time happens twice in America/New_York.**). The note then records "Used the earlier occurrence." ### Rule 6: the 32-bit check The whole seconds are compared with −2,147,483,648 to 2,147,483,647. Outside that, the verdict is **Outside signed 32-bit seconds: 2038 overflow risk.** The upper bound is `2038-01-19T03:14:07Z`. This is a property of systems that store `time_t` or a database column in 32 signed bits, not of Unix time itself. ### Rule 7: verdict order for one instant Epoch zero (**Unix epoch: 1 January 1970.**), then a negative value (**Before the Unix epoch: negative timestamp.**), then the 32-bit range, then a guessed unit, then an assumed zone, then **One instant. Exact to the nanosecond.** The summary line holds the notes, or "The unit was selected or the input includes an explicit offset." ### Rule 8: batches and exports Each non-empty line is parsed with the same options. The verdict counts **n of m values converted.** Copied text keeps failed lines as `Line N: ERROR:` so nothing disappears. CSV output quotes every cell, doubles inner quotes, and prefixes a cell that starts with `=`, `+`, `-` or `@` with an apostrophe so a spreadsheet does not run it as a formula; a negative epoch therefore appears as `'-1`. The columns are line, input, iso, seconds, milliseconds, microseconds, nanoseconds, notes and error. ## Standards and conformance ### RFC 3339: date and time on the internet [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) is a Proposed Standard profile of ISO 8601, updated by [RFC 9557](https://www.rfc-editor.org/rfc/rfc9557). The page reads the `date-time` and `full-date` productions of [§5.6](https://www.rfc-editor.org/rfc/rfc3339#section-5.6), accepts the lower-case `t` and `z` and the space separator that section allows, and writes `Z` for UTC and a numeric offset otherwise. Where it is more lenient: seconds may be omitted and nine fractional digits are kept. Where it stops: RFC 9557's bracketed suffix such as `[Europe/Paris]` is not read; use the zone control instead. ### RFC 9110: HTTP dates [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110) is an Internet Standard (STD 97) that obsoletes RFC 7231. [§5.6.7](https://www.rfc-editor.org/rfc/rfc9110#section-5.6.7) says a sender "MUST generate those timestamps in the IMF-fixdate format" and that HTTP-date "represents time as an instance of Coordinated Universal Time (UTC)". The HTTP row always writes IMF-fixdate in GMT. The input field accepts only that form; the RFC 850 and asctime obsolete forms, which the RFC says a recipient must still accept, can be edited in their own result rows but are not read from the main input. ### POSIX and the Unix epoch [The Open Group Base Specifications Issue 7, §4.16](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16) defines seconds since the Epoch without leap seconds, and the page converts with the same arithmetic: integer nanoseconds, signed, with floor division for negatives. It extends the definition to fractional units; POSIX itself speaks only of seconds. ### IANA time zones Zone names and rules come from the [IANA Time Zone Database](https://www.iana.org/time-zones) as shipped in your browser. The page lists the zones the browser reports and resolves offsets through `Intl.DateTimeFormat`. An older browser may lack a recent rule change; the page cannot know. ### RFC 7519: the JWT fixture The **Use as JWT expiry** value follows the NumericDate definition of [RFC 7519 §2](https://www.rfc-editor.org/rfc/rfc7519#section-2): "the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds". The fixture is rounded down to whole seconds and carries `alg: none`, which [RFC 8725 §3.1](https://www.rfc-editor.org/rfc/rfc8725#section-3.1) tells verifiers to reject by default. It is for testing a verifier, never for use. ### RFC 4180: CSV export The batch CSV follows [RFC 4180 §2](https://www.rfc-editor.org/rfc/rfc4180#section-2) quoting (every field quoted, inner quotes doubled, a header row) and adds the formula-neutralising apostrophe, which is a spreadsheet safety measure outside the RFC. ### ISO 8601 and the ISO rows [ISO 8601-1:2019](https://www.iso.org/standard/70907.html) defines the calendar, ordinal and week dates the ISO picker offers and the basic format `YYYYMMDDTHHmmssZ`. Only its RFC 3339 subset is read from the input field. ## Finding reference ### Checks on a converted instant | Finding | Chip | Meaning | Fix | | --- | --- | --- | --- | | Unit guessed from n digits | Check | The unit came from the digit table, not from you | Select the unit, or add a suffix and apply Read unit suffix | | No offset, read in zone | Check | The civil time was resolved in the input zone | Choose the right zone, then apply Make the offset explicit | | Outside the signed 32-bit seconds range | Check | A `time_t` or 32-bit column cannot hold this value | Store 64-bit seconds or milliseconds; see the Guide | | Before the Unix epoch: negative timestamp | Check | Valid, but some APIs refuse negatives (MySQL `FROM_UNIXTIME`) | Use a date literal where the snippet shows one | | Unit set to unit, Offset in the input, Fits signed 32-bit seconds | Pass | Nothing to do | | ### Values that do not convert | Verdict | Message | Cause | | --- | --- | --- | | Not a format this tool reads. | Use an epoch number, YYYY-MM-DD, ISO date-time, or an HTTP date ending in GMT. Ambiguous date orders are not guessed. | Slash dates, words, exponent notation, separators | | Finer than nanoseconds. | Precision beyond nanoseconds cannot be represented. | Too many fractional digits for the unit | | Outside years 0001 to 9999. | Supported dates run from year 0001 through 9999. | Usually milliseconds read as seconds | | Not a real calendar date. | Invalid calendar date or time. Leap seconds and rolled-over dates are not accepted. | 29 February off a leap year, 31 April, `:60` | | Not a real time in zone. | This local time does not exist in that zone (a clock change skipped it). | Spring-forward gap | | This time happens twice in zone. | This local time occurs twice. Choose the earlier or later occurrence. | Autumn fold, no choice made | | Input needs attention. | Choose a valid IANA time zone, such as America/New_York. | Unknown zone name | | Input needs attention. | Input is limited to 20,000 characters. / Use at most 200 non-empty lines. | Batch too large | ## Guide ### A Date.now() value read as seconds `1700000000000` with Seconds selected fails the range rule. Apply **Interpret as milliseconds** under Heal it; the verdict becomes one instant in November 2023 and History records the change. In Auto mode the same value is read as milliseconds from its 13 digits, with a Check chip reminding you it was guessed. ### A 2038 value Break it loads `2147483648` seconds, one past the signed 32-bit limit. The verdict is **Outside signed 32-bit seconds: 2038 overflow risk.** If the value will be stored in a C `time_t` on a 32-bit build, a 32-bit integer column or an embedded device, store it as a 64-bit integer or as milliseconds in a 64-bit field, and check with the Use in code snippet what your language keeps. ### A date before 1970 `-1` is 1969-12-31T23:59:59Z. Negative values are valid everywhere in the page. The MySQL snippet switches to a `TIMESTAMP` literal because `FROM_UNIXTIME` refuses negatives, and the Python snippet adds to the epoch so it works on every platform. ### A skipped or repeated hour Break it loads `2024-03-10T02:30:00` in America/New_York, a time that never happened. Heal it offers the reading with the offset from before and after the jump, each written with that offset so no other system has to guess. The repeated case, `2024-11-03T01:30:00`, is settled with Earlier or Later next to the input; each button shows its offset. For a batch, write the offset on each affected line instead. ### A leap day that does not exist `2023-02-29T12:00:00Z` fails the calendar rule. Correct the year or the day; the page does not roll dates over. ### Nanosecond precision Break it builds a nanosecond value from your own instant. Every format row shows what survives: ISO keeps nine digits, SQL variants three or six, the HTTP date whole seconds, and the snippet notes say which languages drop digits. ### A batch of lines Paste one value per line. Pick **Copy all as** ISO 8601 or milliseconds and a zone, keep failed lines marked so the output stays aligned with the input, and copy. Use CSV when a spreadsheet is next. ### Confirm a conversion independently ```sh date -u -d @1760000000 # GNU coreutils date -u -r 1760000000 # macOS and BSD python3 -c "from datetime import datetime, timezone; print(datetime.fromtimestamp(1760000000, timezone.utc).isoformat())" ``` All three print 2025-10-09 08:53:20 UTC. For a milliseconds value divide by 1,000 first; the shell `date` takes whole seconds only. ### Break it cases | Button | Loads | What it shows | | --- | --- | --- | | Epoch zero | `0` seconds | The epoch verdict | | Before 1970 | `-1` seconds | A negative timestamp | | 2038 overflow | `2147483648` seconds | The 32-bit range check | | Mix up s and ms | Your instant in milliseconds, read as seconds | The range failure and Interpret as milliseconds | | Nanosecond precision | Your instant with `123456789` ns added | What each format keeps | | Invalid leap day | `2023-02-29T12:00:00Z` | The calendar rule | | DST missing hour | `2024-03-10T02:30:00`, America/New_York | The gap repairs | | DST repeated hour | `2024-11-03T01:30:00`, America/New_York | The Earlier and Later choice | Cases that are a way of writing an instant build on your own input; the fixed dates are reserved test values. Revert restores what you had. ## Worked example The opening value is the reserved sample `1760000000`, labelled Example: a synthetic value, not read from any live system. Ten digits put it in the seconds band, so the verdict is **One instant, assuming seconds.** with the note "Assumed seconds from digit count. Override the input unit if needed." The chips read Unit guessed from 10 digits (Check) and Fits signed 32-bit seconds (Pass). The readable line is Thursday, 9 October 2025, 08:53:20 UTC; the facts line says day 282 of the year, ISO week 41, common year. Every format shows `2025-10-09T08:53:20Z`, `1760000000000` milliseconds, `Thu, 09 Oct 2025 08:53:20 GMT`, `2025-10-09 08:53:20` for SQL. Selecting Seconds in the unit control turns the first chip into Unit set to seconds and the verdict into **One instant. Exact to the nanosecond.**, because the reading is no longer a guess. Shift shows 07:53:20 and 09:53:20 as the one-hour targets; Snap shows 2025-10-06 as the start of the week and 2025-10-31 23:59:59 as the end of the month. ## For agents The Tamperbox MCP server exposes two MCP tools: use `search` to inspect the catalog and schema, then use `execute` to call an operation through `tamperbox.request`. The timestamp page maps to three `POST /v1/tools/...` operations: | Operation | Required input and result | Notes | | --- | --- | --- | | `timestamp_to_iso` | A text artifact containing one epoch or UTC calendar value; returns an ISO text artifact | No live clock and no zone inference | | `timestamp_convert` | `input` of up to 20,000 characters and 200 lines; returns parsed rows plus the requested export | Per-line errors stay in the result; nanoseconds are decimal strings | | `timestamp_adjust` | One `input`; returns ISO and nanosecond values, formatted output and facts, plus optional code or JWT fields | Shift with `delta`, or snap with `period` and `edge`; the JWT fixture is unsigned | Keep these with any conclusion: a guessed unit is a hint from the digit count; a time read without an offset depends on the zone supplied and on the zone database of the runtime; MCP inputs are processed on the Tamperbox server, so keep sensitive values on the browser page. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) for the calling pattern. ## Limits - Instants run from year 0001 to 9999 in UTC; precision finer than a nanosecond is refused, not rounded. - Auto unit detection is a digit count. Select the unit when it matters. - Zone rules are the browser's. A recent rule change may be missing from an older browser. - No natural-language parsing, no slash dates, no leap seconds, no RFC 9557 zone suffixes. - Shifts are elapsed time; calendar snapping and the display rows follow the display zone; ISO and HTTP rows are always UTC. - Now and the relative age use the device clock. - Input is limited to 20,000 characters, 200 non-empty lines and 500 characters per value; templates to 100 characters. - Nothing is sent or stored; the JWT handoff moves one value through tab memory. ## References - [RFC 3339, Date and Time on the Internet: Timestamps](https://www.rfc-editor.org/rfc/rfc3339). Proposed Standard, July 2002; updated by RFC 9557. Sections used: [4.3](https://www.rfc-editor.org/rfc/rfc3339#section-4.3), [5.6](https://www.rfc-editor.org/rfc/rfc3339#section-5.6), [5.8](https://www.rfc-editor.org/rfc/rfc3339#section-5.8). - [RFC 9557, Date and Time on the Internet: Timestamps with Additional Information](https://www.rfc-editor.org/rfc/rfc9557). Proposed Standard, April 2024; updates RFC 3339. Not implemented; named so readers know the suffix form is not read. - [RFC 9110, HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110). Internet Standard (STD 97), June 2022; obsoletes [RFC 7231](https://www.rfc-editor.org/rfc/rfc7231). Section used: [5.6.7](https://www.rfc-editor.org/rfc/rfc9110#section-5.6.7). - [RFC 5322, Internet Message Format](https://www.rfc-editor.org/rfc/rfc5322). Draft Standard; updated by [RFC 6854](https://www.rfc-editor.org/rfc/rfc6854). Section used: [3.3](https://www.rfc-editor.org/rfc/rfc5322#section-3.3) for the email date row. - [RFC 7519, JSON Web Token](https://www.rfc-editor.org/rfc/rfc7519). Proposed Standard; updated by RFC 8725. Section used: [2](https://www.rfc-editor.org/rfc/rfc7519#section-2) (NumericDate). - [RFC 8725, JSON Web Token Best Current Practices](https://www.rfc-editor.org/rfc/rfc8725). Best Current Practice. Section used: [3.1](https://www.rfc-editor.org/rfc/rfc8725#section-3.1). - [RFC 4180, Common Format and MIME Type for CSV Files](https://www.rfc-editor.org/rfc/rfc4180). Informational; updated by [RFC 7111](https://www.rfc-editor.org/rfc/rfc7111). Section used: [2](https://www.rfc-editor.org/rfc/rfc4180#section-2). - [RFC 850, Standard for Interchange of USENET Messages](https://www.rfc-editor.org/rfc/rfc850). Obsoleted by [RFC 1036](https://www.rfc-editor.org/rfc/rfc1036); its date form survives only as the obs-date of RFC 9110 §5.6.7 and in the RFC 850 result row. - [The Open Group Base Specifications Issue 7, 2018 edition, §4.16 Seconds Since the Epoch](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16). - [IANA Time Zone Database](https://www.iana.org/time-zones). - [ISO 8601-1:2019, Date and time, Representations for information interchange, Part 1: Basic rules](https://www.iso.org/standard/70907.html). - [ECMA-262, Time values and time range](https://tc39.es/ecma262/#sec-time-values-and-time-range). --- # Website Down Checker How the website down checker requests a site from the Tamperbox server, where it places a failure, what each outcome means for visitors and owners, and how to confirm a fix. Canonical: https://docs.tamperbox.dev/tools/website-down-checker/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A public web address on port 80 or 443, or a host name that starts at https:// Outputs: A verdict, the outcome finding, the DNS, Connect / TLS and HTTP stages, the status code, time to first byte, total time, redirect count and final address Limitations: One request from one location at one moment; connection and TLS failures share one stage; any answer below 500 counts as up The tool page is [tamperbox.dev/website-down-checker](https://tamperbox.dev/website-down-checker). It loads `tamperbox.dev` and waits for you to run a live check, says in one sentence whether the site answers from the probe’s location, and shows the stage where a request stopped. This page is the long version: what the request does, every rule that decides the verdict, what each outcome means, and how to fix and confirm each one. <div class="tb-callout"><strong>Where processing happens:</strong> typing an address is read in your browser only. Nothing is sent until you press Check now or Enter. Then the Tamperbox server makes one request to the address, follows up to five redirects within ten seconds, and returns what it saw. Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. Sample addresses on the reserved <code>.example</code> zone are answered in the browser from a fixture and never reach the network.</div> ## What the tool answers Three questions, in the order a person with a broken site asks them: 1. **Does it answer this probe?** A successful request establishes reachability from the current server location. It cannot establish availability for every visitor or rule out regional, account-specific or intermittent failures. 2. **If it is down, where does it stop?** The name does not resolve, the connection or TLS handshake fails, nothing answers within ten seconds, the redirects never end, or the application answers with a server error. 3. **If it is up, is it slow or answering with something other than the page?** A total time over three seconds, or a 4xx status, are worth knowing even when the site counts as up. The verdict answers the first question in one sentence. The Status section and its three stages answer the second. The findings and the Response table answer the third. ## Inputs ### A web address Type `example.com`, `www.example.com/status` or a full address such as `https://example.com/login`. Without a scheme the address starts at `https://`. A path and query are kept and requested as written; a fragment (`#section`) is dropped because it never reaches a server. The check is manual. Typing only says "Ready to check" and what will be requested; nothing leaves the browser until you press **Check now** or Enter. A sample address on `.example` is the exception: it is answered at once from the fixture because no request is made. Refused before any request, with the reason in the field: | Input | Message | | --- | --- | | A space anywhere | A web address cannot contain spaces. | | A scheme other than http or https | Use an http:// or https:// address, not ftp://. | | `mailto:`, `tel:`, `javascript:`, `data:` or `file:` | Enter a web address, such as example.com or `https://example.com/page`. | | A user name or password in the address | Remove the user name and password from the address. Heal it offers to remove them. | | A port other than 80 or 443 | Only the standard ports (80 and 443) are checked. Heal it offers the standard port. | | An IP address | Enter a host name. Addresses written as IP numbers are not checked. | | A single label such as `intranet` | Add the top-level domain, such as intranet.com. | ### Pasting and dropping A pasted address is tidied before it is read: surrounding quotes and angle brackets are removed, as is trailing punctuation from a sentence. The tool takes the whole address, path included, because a page can be down while the home page works. Text that is not an address stays as pasted so the error above can explain it. Typing is never rewritten. A `.txt` file dropped on the page or opened with **Add a file** is read in the browser, and its text goes into the field the same way. ## Reading the result ### Verdict and chips The verdict is one of four sentences: "host is up.", "host is up, but slow.", "host is answering with errors." or "Site unavailable:" followed by the reason. The line under it says whether this was a live check from our server or a sample answer. The chips are buttons: the first shows the status or the stage the request stopped at and scrolls to Status; the second shows the total time and scrolls to Response. Under the chips, two items say where the input went: typing stays in the browser, and Check now means one request from our server. ### Findings Advice follows the observed outcome: DNS, connection, HTTP failure, timeout or slow response. Reachable results also show two notes for visitors who cannot open the site. The outcome is followed by a redirect finding when redirects occurred, a first-byte finding when timing is available, no request error occurred and the outcome is not slow, and the relevant visitor advice. Two or more passing findings are grouped under an expandable **checks passed** row; a single pass stays visible. ### Status One word (Up, Slow, Erroring or Down), the address requested with an arrow to the final address if the redirects moved it, and when the check ran. Under it, three stages in order: **DNS**, **Connect / TLS** and **HTTP**. The stage that failed is marked Failed; stages after it are marked Skipped, because the request never reached them. ### Response A table of what came back: the status, the recorded duration of the final hop, the total time (or the time until it failed), the number of redirects followed, and the final address (or the address tried). ### History History follows the current result evidence. Break it and Heal it record input changes, newest first. **Revert** restores the input before the latest recorded change; **Reset input** restores the input before the first retained change and clears the list. **Restore input before this break** under Heal it also reverts the latest change. These actions reload and check the restored input. Restoring a public address can therefore send a new request, including on the two tools whose ordinary typing waits for a run button. Editing or pasting a new input clears History. The list lives in the current page; it is not saved monitoring data and does not restore an old network response. ### Take it further Only links with an available result value appear. | Follow-up | Value carried | When offered | | --- | --- | --- | | [TCP Ping](https://tamperbox.dev/tcp-ping) | Final host and port | A live result without a DNS-stage failure | | [SSL Checker](https://tamperbox.dev/ssl-checker) | Final host | No DNS-stage failure and the final scheme uses port 443 | | [Website Hosting](https://tamperbox.dev/website-hosting) | Final host | No DNS-stage failure | ### Related checks and input transfer Check the rest carries the current address to a sibling tool. Take it further carries the specific value listed above. Pasted file contents are not transferred through these links. Transfers temporarily use browser `sessionStorage` with a one-use random token in the URL fragment; the input itself is not in the URL. The destination accepts a transfer for less than one minute and removes the token. Manual destination tools wait for their run button or Enter. Each destination collects new evidence. A follow-up link does not confirm the original verdict or repair the remote site. ### Result cards Six expandable cards below the result explain its meaning, give a beginner explanation, offer an agent prompt, describe good practice, suggest fixes and state limitations. Their text follows the current result; it is not another measurement. Open a card for its full explanation and the relevant [Method](#method) or [Guide](#guide). The agent prompt can be copied for review; copying it does not run a repair or send it to an agent. ## Method The page sends the address to `/api/web/uptime`. The server makes the request and the page judges the answer. Findings use these statuses: | Severity | Shown as | Meaning | | --- | --- | --- | | Problem | FAIL | The probe could not retrieve a successful response | | Warning | CHECK | The probe observed a slow response | | Information | INFO | Interpret the response in its observed scope | | Passed check | PASS | The observed response or final-hop timing met this check | ### The request 1. **Address check.** The server accepts HTTP and HTTPS addresses up to 2,048 characters, on port 80 or 443, without credentials. Anything else is refused before DNS. 2. **DNS.** The host's A and AAAA records ([RFC 1035, section 3.4.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.4.1); [RFC 3596, section 2](https://www.rfc-editor.org/rfc/rfc3596#section-2)) are resolved over Cloudflare's DNS-over-HTTPS JSON interface, following CNAME aliases. Both lookups must complete; an empty answer for one family is fine. A name that does not exist (RCODE 3, Name Error, [RFC 1035, section 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1)), an inconclusive or truncated answer, a name with no address at all, and a name that resolves to any non-public address (the special-purpose ranges in the [IANA registries](https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml), such as [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3) private space) all stop here. ### Connection, response and limits 3. **Connection and TLS.** The server opens the connection and, for `https://`, the TLS handshake ([RFC 8446, section 4](https://www.rfc-editor.org/rfc/rfc8446#section-4)). The runtime that makes the request does not report TCP and TLS separately, so a refused port, a reset, an expired or wrong certificate and a failed handshake are all reported as one stage. 4. **HTTP.** A `GET` with the user agent `Mozilla/5.0 (compatible; TamperboxBot/1.0; +https://tamperbox.dev/bot)`, `Accept: */*`, `Accept-Encoding: identity`, and no cookies. Redirects are not followed automatically: each 301, 302, 303, 307 or 308 is read, its `Location` ([RFC 9110, section 10.2.2](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.2)) resolved against the current address and checked like the first address, and the next request made. The body is never read; the run stops as soon as the final status and headers arrive. 5. **Limits.** At most six requests (five redirects), one ten-second budget for the whole run, DNS and redirects included. [RFC 9110, section 15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4) leaves the redirect limit to the client ("A client SHOULD detect and intervene in cyclical redirections"); five is a stricter bound than most browsers, which allow around twenty, and can stop a legitimate but longer chain. ### Times Two times are measured on the server. **First byte** uses the final hop’s recorded duration, including its DNS validation and the wait for response headers. It is not a separately measured browser time to first byte. **Total** is the whole run, from before the first DNS lookup to the final status. A long redirect chain makes the total larger than the final page deserves; compare the two to see where time went. ### The outcome The following table summarizes how to interpret the observation. Its guide labels are not emitted finding IDs; the advice actually shown is listed in [Finding reference](#finding-reference). | Rule | Guide label | Interpretation | Verdict | | --- | --- | --- | --- | | The request stopped at DNS | `dns` | FAIL | Site unavailable | | The request stopped connecting or in TLS | `connect` | FAIL | Site unavailable | | The ten-second budget ran out | `timeout` | FAIL | Site unavailable | | The redirects looped, exceeded five, had no `Location`, or pointed at a private address or another port | `redirect` | FAIL | Site unavailable | | Status 500 or higher | `http` | FAIL | answering with errors | | Status below 500, total time over 3,000 ms | `slow` | CHECK | up, but slow | | Status 400 to 499 | `client` | INFO | up | | Status below 400 | `up` | PASS | up | Why 500 is the line: [RFC 9110, section 15.6](https://www.rfc-editor.org/rfc/rfc9110#section-15.6) defines 5xx as "the server is aware that it has erred or is incapable of performing the requested method", while a 4xx ([section 15.5](https://www.rfc-editor.org/rfc/rfc9110#section-15.5)) is the server working and refusing this request. A 403 from a bot filter, a 404 for a moved page and a 429 rate limit ([RFC 6585, section 4](https://www.rfc-editor.org/rfc/rfc6585#section-4)) all prove the site is reachable and answering. The status is shown so you can see whether it answered with the page. Why three seconds: it is a judgment, not a standard. No RFC defines slow; three seconds is far above what a cached page or a healthy origin needs, so crossing it means something is worth looking at. The threshold applies to the total, so a site that is fast but redirects three times can cross it. ### Stage placement DNS, TCP and TLS timing fields are currently null. The stage panel derives its labels from a reported failure rather than measuring three independent phases. Policy failures can therefore be displayed under a broader stage label. Preserve the literal error code when diagnosing the cause. The server reports a failure with a stage and a code. Stages map to the three columns as follows: | Server stage | Column marked Failed | Codes you may see | | --- | --- | --- | | `dns` | DNS | `dns_error`, `unsafe_target` | | `connect` | Connect / TLS | `upstream_error` and runtime connection errors | | `timeout` | HTTP, "No answer in time" | `timeout` | | `http` (redirects) | HTTP | `redirect_loop`, `redirect_limit`, `redirect_unsafe`, `missing_location` | | none, status ≥ 500 | HTTP, with the status | | ## Standards and conformance ### RFC 9110, HTTP Semantics Implemented: status code classes ([section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15)) decide the outcome; redirection ([section 15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4)) with the five redirect codes and `Location` resolution as a URI reference against the current address ([section 10.2.2](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.2)); loop detection as section 15.4 asks of clients. Where it stops: a 303 is followed with `GET`, as all methods are `GET` here; `Retry-After` on a 503 or 429 ([section 10.2.3](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.3)) is not shown; the response body is not read, so a 200 page that says "maintenance" counts as up. RFC 9110 obsoletes RFC 7231, which older references cite for the same rules. ### RFC 1035 and RFC 3596, DNS Implemented on the server through DNS-over-HTTPS: A and AAAA queries, CNAME chains with a loop check, Name Error as non-existence. Stricter than a browser: both address families must resolve without error, and every address must be public. A browser that tries only IPv4 might reach a site this check calls down at DNS; the finding detail says which rule stopped it. ### RFC 8446, TLS 1.3 The handshake is the runtime's, with its trust store and SNI set to the host. The check does not report the protocol version, cipher or certificate; a TLS failure appears only as a Connect / TLS failure. For the certificate itself, use the [SSL certificate checker](https://docs.tamperbox.dev/tools/ssl-checker/), which opens a dedicated TLS probe and reports every certificate. ### RFC 6585, status 429 Read as an answer from a working server: INFO, not down. ## Finding reference ### Advice emitted by the browser These titles describe the reported outcome, not stable operation identifiers. | Title | Severity | Observed condition | Next check | | --- | --- | --- | --- | | The name does not resolve | FAIL | The probe reports a DNS-stage failure | Check authoritative records and another resolver; inspect the error code | | Connection or TLS failed | FAIL | The runtime reports a connection-stage failure | Inspect the certificate, firewall, load balancer and listener | | The server answers with an error | FAIL | The observed final status is 500 or higher | Compare application logs with the request time | | No answer within 10 seconds | FAIL | A timeout or exhausted request budget | Read the literal error and final attempted address before diagnosing a timeout | | Answered status | PASS / INFO | A non-slow response below 400 passes; a non-slow 4xx response is informational | Read the status before treating it as the page you wanted | | Redirects could not be followed to the end | FAIL | An HTTP-stage error stopped the redirect chain | Read the recorded error and last attempted address | | Followed n redirects | INFO | At least one redirect was followed | Inspect the final address and remove unnecessary hops | | First byte after n ms | PASS / CHECK | No request error, a measured final-hop duration and a non-slow outcome; over 3,000 ms warns | Compare final-hop duration with total time | | Up, but slow | CHECK | A reachable response took over 3,000 ms in total | Compare redirects and server processing with an independent client | | If it will not open for you | INFO | The probe received a reachable response | Compare a browser, another network and any local proxy | | If only some visitors see it down | INFO | The result is one observation from one place | Check independent locations and retain unavailable results | ### Evidence separate from advice Status, redirect count, final address and recorded durations remain in the Status and Response panels as well as the applicable findings. Read these values together rather than treating a passing timing finding as proof of worldwide availability. A 4xx status still counts as reachable in this tool, even though it may represent a missing page, denied access or rate limiting. The total-time threshold does not measure how long the page takes to render in a browser. An HTTP-stage error selects the redirect outcome; a budget error selects timeout. Other unrecognized error stages use the connection outcome while the Status panel retains the reported code. Use the literal code and attempted address as the diagnostic evidence. Do not infer that all visitors see the same failure from the wording of a headline. ## Guide ### It works here but not for me The check reached the site from this server. Compare the failing client’s request, network and session before locating the cause. 1. Open the site on mobile data instead of your usual network. If it loads, compare DNS, routing, proxies and access policies on the failing network. 2. Turn off a VPN, proxy or ad blocker and reload. 3. Clear the DNS cache: restart the browser, or run `sudo dscacheutil -flushcache` (macOS), `ipconfig /flushdns` (Windows) or `resolvectl flush-caches` (Linux). 4. Compare what your resolver returns with a public one: `dig +short example.com` and `dig +short example.com @1.1.1.1`. Different answers point at a stale or filtering resolver. ### The name does not resolve 1. At the registrar, check that the domain has not expired and is not on hold. 2. Check that the nameservers at the registrar are the ones that hold your records: `dig +short NS example.com` should list them. 3. Check that the exact host has an address: `dig +short A www.example.com` and `dig +short AAAA www.example.com`. A record for `www` does not cover the bare domain, and the reverse. 4. If the host resolves to a private address such as `10.0.0.5`, it is reachable only inside your network. Publish a public address. Confirm with the check again: DNS should be Passed. ### Connection or TLS failed 1. Check the certificate with the [SSL certificate checker](https://docs.tamperbox.dev/tools/ssl-checker/) or `openssl s_client -connect example.com:443 -servername example.com </dev/null`. An expired, self-signed or wrong-name certificate fails here. 2. Check the port is open from outside: `nc -vz example.com 443`, or use [TCP Ping](https://docs.tamperbox.dev/tools/tcp-ping/) for the host and port, retaining unavailable-region results. 3. Check the server, load balancer and firewall are running and accept connections on port 443 (or 80). ### Server errors 1. Read the application log for the time of the check. 2. A 502 or 504 comes from a proxy that got no good answer from the application behind it ([RFC 9110, sections 15.6.3 and 15.6.5](https://www.rfc-editor.org/rfc/rfc9110#section-15.6.3)); check that the backend runs and listens where the proxy points. 3. A 503 ([section 15.6.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.6.4)) is often a maintenance switch or an overloaded pool; check whether it was deliberate. 4. Roll back the last deployment if the errors began with it. Reproduce outside Tamperbox: `curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' -L --max-redirs 5 --max-time 10 https://example.com/`. ### No answer in time 1. Check server load and whether the application accepts requests at all, for example with `curl -v` from the server itself. 2. Look for a firewall rule that drops traffic instead of rejecting it; drops look like timeouts. 3. Check from more than one region; a timeout only from some networks points at routing or a regional filter. ### Redirects never end 1. Trace each hop with the [redirect checker](https://tamperbox.dev/redirect-checker) or `curl -sIL --max-redirs 10 http://example.com/`. 2. Look for two rules that undo each other: www to bare and bare to www, or http to https behind a proxy that tells the application the request was http. 3. Point the first address straight at the final `https://` page, in one redirect. ### Slow 1. Compare First byte with Total in Response. If First byte is most of the total, the final hop dominates; earlier hops account for the remainder. The final-hop duration includes DNS validation and connection setup, so it cannot isolate application processing. 2. Cache what does not change, and cut redirects to one. 3. Check again at a quiet hour to tell load from a constant cost. ### Break it cases Break it loads a case that shows each failure. A site cannot be made to fail on request, so these are sample hosts answered by a fixture; **No such host** is built from your own domain. | Case | What it loads | What to look at | | --- | --- | --- | | Connection refused | `down.harbor-supply.example` | Connect / TLS Failed; Down | | Certificate expired | `expired.harbor-supply.example` | Connect / TLS Failed, the certificate named in the message | | Server errors (503) | `error.harbor-supply.example` | Erroring; HTTP Failed with 503 | | No answer in time | `outage.harbor-supply.example` | HTTP Failed, "No answer in time" | | Slow to answer | `slow.harbor-supply.example` | Up, but slow; the time chip turns CHECK | | No such host | `nohost.` plus your domain | DNS Failed | Break it replaces the field with an adapted input or a labelled fixture. Use History to Revert the latest change or Reset input to the starting input; restoring a live address runs a new check. ## Worked example The page loads `tamperbox.dev` in the field without sending a request. Press **Check now** to inspect `https://tamperbox.dev/`. The result is a live observation, so status codes, redirects and timings can change between runs. Start with the returned status and observation time. An HTTP answer below 500 is classified as reachable, including 403 and 404; that does not mean the visitor received the intended content. Compare total time with time to the final response, then inspect the final address. The DNS, Connect / TLS and HTTP panels explain the reported failure stage, but they are not three independent tests. To exercise failures without depending on a public outage, choose a reserved-domain Break it case. A fixture is labelled as a sample and does not contact that host. Replace the field with your own address to return to live mode and press Check now again. Compare another network or independent monitor before concluding that an outage affects everyone. ## For agents Use the Tamperbox MCP `search` tool to inspect the schema, then `execute` with `tamperbox.request` to call `POST /v1/tools/website_down_checker`. Supply the required `url` field as a full public HTTP or HTTPS URL. The operation is named `website_down_checker`; the browser page’s hyphenated identifier is not the API operation name. The response contains regional observations, requested regions and unavailable-region details. Unconfigured regional probes are explicitly unavailable; one successful server observation does not establish global reachability. Keep the input, observation time, source limitations and inconclusive results with any summary. Browser fixtures are demonstrations, not live MCP targets. Do not turn missing evidence into a passing check or infer that an inaccessible resource has been deleted. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/), [Code mode](https://docs.tamperbox.dev/mcp/code-mode/) and [Security and privacy](https://docs.tamperbox.dev/reference/security/). ## Limits - One request, from one place, at one moment. Regional probing is not configured; the server reports the three regions it was asked for as unavailable. - Any answer below 500 counts as up, including 403 and 404. - Connection and TLS failures share one stage. - The response body is not read, so a page that answers 200 with an error message counts as up. - Only ports 80 and 443, only public addresses, at most five redirects and ten seconds. - A site can block the TamperboxBot user agent while it works for people. - Live checks are rate limited. - Explicit sibling-tool transfers use temporary browser storage; diagnostic results are not a monitoring history. ## References - [RFC 9110, HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110): [section 10.2.2](https://www.rfc-editor.org/rfc/rfc9110#section-10.2.2) Location, [section 15.4](https://www.rfc-editor.org/rfc/rfc9110#section-15.4) redirection, [section 15.5](https://www.rfc-editor.org/rfc/rfc9110#section-15.5) client errors, [section 15.6](https://www.rfc-editor.org/rfc/rfc9110#section-15.6) server errors. Obsoletes RFC 7231. - [RFC 6585, Additional HTTP Status Codes](https://www.rfc-editor.org/rfc/rfc6585#section-4), section 4, 429 Too Many Requests. - [RFC 1035, Domain Names: Implementation and Specification](https://www.rfc-editor.org/rfc/rfc1035), sections [3.4.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.4.1) and [4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1). - [RFC 3596, DNS Extensions to Support IPv6](https://www.rfc-editor.org/rfc/rfc3596#section-2), section 2, the AAAA record. - [RFC 1918, Address Allocation for Private Internets](https://www.rfc-editor.org/rfc/rfc1918#section-3), section 3, and the [IANA IPv4 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml). - [RFC 8446, TLS 1.3](https://www.rfc-editor.org/rfc/rfc8446#section-4), section 4, the handshake. --- # Website Hosting Checker How Tamperbox follows website DNS, maps public addresses to networks, and compares the apex with www. Canonical: https://docs.tamperbox.dev/tools/website-hosting/ Updated: 2026-10-25 Applies to: tamperbox.dev, October 2026 Prerequisites: a domain name or pasted A, AAAA and CNAME evidence Outputs: the apex and www DNS chains, public addresses, network attribution and routing findings Limitations: Public observations are time-sensitive and do not prove ownership, intent or private configuration The tool page is [tamperbox.dev/website-hosting](https://tamperbox.dev/website-hosting). It opens with a live lookup of `mozilla.org`; replace it to inspect your own target. This guide documents the actual input path, evidence contract, classifications and independent verification steps. <div class="tb-callout"><strong>Where processing happens:</strong> input cleanup and report rendering happen in the browser. Direct public IP addresses are sent for network-information lookup, even when pasted. Live checks send only the validated public target to the Tamperbox server and the public services required for the lookup. The page stores no report; History is local to the current browser session.</div> ## What the tool answers The checker answers which public network appears to serve a website and whether the apex and www names take materially different routes. Its conclusion is deliberately narrower than an ownership or security claim. A displayed provider, product, name or passing check means that the listed public evidence matched a documented rule at the observation time. Every conclusion is paired with evidence. The opening verdict is a summary for orientation, while Findings contains the actionable interpretation and the later result sections retain the underlying records, addresses, fields or names. If a conclusion matters operationally, verify that evidence through an authoritative account or an independent standards-aware client before changing production. ## Inputs ### Accepted source Enter a domain or one or more IP addresses separated by whitespace or commas. Domains trigger CNAME, A and AAAA lookups; unless the name already starts with `www.`, the tool also checks its `www` name. Direct public IP input triggers network-information requests. Pasting an IP address is therefore not an offline mode. Special-use addresses are classified locally without a network-information lookup. Invalid IPv4 octets are refused. Text files are read in the browser. The resulting input follows the same classification rules as the field; reading a file locally does not make a domain or public-IP lookup offline. Cleanup keeps an already accepted record intact and otherwise tries unwrapping a single-line address. Unusable text remains visible for correction. ### When work runs Domain input runs after a 600-millisecond typing pause. Enter runs it immediately; pasted records run immediately. Drops and page-wide paste use the same input loader. Leaving the field applies cleanup and reruns only when cleanup changes the text. Each edit aborts the previous request and increments a generation marker. A slower old response therefore cannot replace a newer result, and clearing the source immediately clears copyable output. The opening input uses the same parser and processing path as a replacement. The labelled live default sends the same requests as another domain. ## Reading the result ### Verdict and privacy The verdict states what the available evidence supports and uses pass, check, fail or informational status consistently. Pass means the bounded rule succeeded. Check means a human should confirm context. Fail means a concrete operational rule was violated. Info describes a limitation, absence or neutral fact and must not be promoted into success or failure by an automated reader. Two privacy lines distinguish browser-only work from live lookup work. The Checked line names the cleaned input and source mode. Copy result is hidden while work is pending, after an error and when input is empty, preventing a stale report from being exported as current. ### Findings and evidence Findings are ordered with failures first, then checks, informational notes and passes. Repeated passing details can fold into a disclosure so that exceptions remain visible. Each item states the observation and its consequence; any remediation is scoped to the evidence rather than presented as a universal configuration recipe. Evidence sections follow Findings and precede History. They are the audit trail for the verdict. A provider label derived from a catalog remains an inference, while a literal record or response field remains an observation. This distinction matters when signatures are incomplete, white-labelled or stale. ### History and handoffs History records intentional input replacements, including Break it examples and their repairs. Revert restores the prior input and runs it again, including live requests when applicable; Reset input returns to the value at the beginning of the recorded sequence. History is not monitoring, persistence or an account log. Check the rest carries the current input to other tools in Domains & hosting. Take it further offers [ASN](https://docs.tamperbox.dev/tools/asn-lookup/) and [reverse DNS](https://docs.tamperbox.dev/tools/reverse-dns/) checks for an observed public address with registry evidence. Derived aliases can be sent to the [CDN and Proxy Detector](https://docs.tamperbox.dev/tools/cdn-detector/) or [Website Technology Detector](https://docs.tamperbox.dev/tools/website-technology/). A public hostname can be sent to [TCP Ping](https://docs.tamperbox.dev/tools/tcp-ping/) on port 443; this tests TCP reachability, not HTTPS correctness. Fixture results do not offer that live reachability handoff. Each receiving tool runs its own check; agreement is not guaranteed. Explicit tool links transfer the input through temporary browser `sessionStorage` and, when needed, a same-origin browser channel. The URL fragment contains a random transfer token, not the input. Transfers are accepted for less than one minute, consumed once, and bound to the destination path. The destination removes the token from its address. Ordinary documentation links and direct visits do not restore a previous input; if transfer storage is unavailable, the link still opens the tool. ## Method ### Validation and collection Before collection, the same domain validation runs in the browser and on the server boundary. Requests are restricted to supported public DNS names and HTTPS roots, redirects are bounded, response sizes are capped and abort signals are propagated. These limits make the observation reproducible and prevent an entered value from becoming an unrestricted network fetch. Use the input modes above to determine which requests run. DNS evidence comes from a public recursive view and can reflect cache state. Local classification cannot add observations absent from the supplied evidence. A server lookup is a fresh observation, not confirmation that cached or pasted evidence is still current. ### Classification rules The lookup resolves the entered name and its www counterpart, follows bounded CNAME chains, collects A and AAAA addresses and maps public prefixes to a maintained network catalog. [RFC 1034 section 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2) says an alias must not coexist with other data; contradictory chains are not silently flattened. The comparison is based on public routing evidence, not a contract with the hosting company. No confidence percentage is invented. When sources disagree, the disagreement is a finding. When a source is unavailable, the affected conclusion becomes informational or inconclusive rather than silently using a previous result. Catalog matches are exact bounded rules; unknown is a valid outcome. ### Ordering and export The renderer calculates all findings from the current observation before updating the verdict, chips, evidence and landing cards. Status priority is fail, check, info, pass. Stable secondary ordering keeps repeated runs readable without changing severity. The Markdown mirror and Copy result output preserve input, summary, findings and important evidence in text form. They do not embed secrets, browser state or the expanded educational cards. Agents should cite the observation time and limitation alongside any exported conclusion. ## Standards and conformance ### Applied specifications | Source | Rule used | Boundary | | --- | --- | --- | | [RFC 1034 section 3.6.2](https://www.rfc-editor.org/rfc/rfc1034#section-3.6.2) | A CNAME aliases one owner to another canonical name | At most eight safe hops are followed | | [RFC 1035 section 3.4.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.4.1) | A maps a name to an IPv4 address | Addresses are displayed; reachability is not tested | | [RFC 3596 section 2.1](https://www.rfc-editor.org/rfc/rfc3596#section-2.1) | AAAA carries an IPv6 address | IPv6 presence is reported, not path quality | | [RFC 6890 section 2.2](https://www.rfc-editor.org/rfc/rfc6890#section-2.2) | Special-purpose blocks have defined reachability properties | Non-public destinations are flagged | These references define the records and message semantics, not the provider catalogs. A catalog is product logic and can lag branding, acquisitions or custom deployments. Where a standard permits several valid configurations, the tool reports the observed form and avoids declaring one commercial pattern universally correct. ### Where conformance stops The checker is an observer, not an authoritative DNS server, browser, certificate monitor, mail receiver or provider control plane. It does not claim protocol conformance for the target. It applies selected validation and interpretation rules to bounded evidence and exposes the boundary where a fuller protocol operation would begin. The phrase “public” refers to the server's Internet view. Private split-horizon answers, authenticated dashboards and regional routing can differ. Cached answers can remain until TTL expiry, and HTTP intermediaries can transform what the origin sent. ## Finding reference ### Emitted findings | Finding | Severity | Meaning | Repair or next check | | --- | --- | --- | --- | | Has no address | Fail | The chain ends without A or AAAA | Repair the target or remove the broken alias | | Points at a non-public address | Fail | Public DNS exposes a special-use destination | Publish a public address or keep the name private | | Uses a different network | Check | Apex and www map to different networks | Verify redirects and intended split before editing DNS | | IPv6 only | Info | No IPv4 destination was found | Add A unless IPv6-only service is deliberate | | No IPv6 | Info | Only IPv4 was observed | Consider AAAA after the origin and CDN support it | | Served through a CDN | Info | The visible network is an edge | Use CDN Detector to inspect response clues | | Network not looked up | Info | Attribution failed for an address | Retry and inspect the address independently | Wording can include the observed name, count, provider or status. Automated consumers should use the supplied status and evidence rather than parsing the English title as a permanent identifier. A missing finding is not evidence that the corresponding external condition is absent when its source could not be collected. ### Status handling | Status | Consumer action | What not to infer | | --- | --- | --- | | Pass | Preserve the evidence and continue normal review | Permanent correctness, ownership or availability | | Check | Confirm intent and inspect the named evidence | Definite compromise or outage | | Fail | Prioritise the concrete broken rule and verify independently | That every user sees the same failure | | Info | Carry the limitation or neutral fact with the report | Success merely because no failure was emitted | ## Guide ### Verify independently Start with an authoritative or widely used command-line client. For DNS, use `dig` with the exact record type and compare every returned owner, target and TTL. Add `+trace` only when delegation matters; a trace and a recursive answer solve different questions. For HTTPS, use `curl -I --location https://host/` and retain each hop and response field. For certificates, use an established TLS client and a CT monitor you trust. Repeat from another network when geography or split routing could matter. Save the observation time and the original evidence before editing. After a DNS change, wait at least the prior TTL and then query both the intended authorities and independent recursive resolvers. ### Repair safely Do not delete an unfamiliar record or reroute a public name merely because a catalog labels it. First identify the owning service, deployment repository or provider account. Confirm whether the item is current, a migration remnant, a failover path or a delegated responsibility. Make the smallest reversible change, keep the prior value, and have a rollback trigger. Re-run this page after propagation, then verify the user-visible service. A clean public lookup cannot prove application health. Conversely, an informational unknown does not require a speculative change. ### Diagnose conflicting evidence When two signals disagree, ask whether they describe different layers: apex versus www, resolver cache versus authority, CDN edge versus origin, entered host versus redirected host, or certificate history versus current DNS. Compare literal evidence before comparing labels. The disagreement itself often reveals a migration or intermediary. If a lookup fails, preserve the error and retry once. Repeated timeouts are not equivalent to empty data. Use the specialist tool linked by the finding for deeper parsing rather than converting an inconclusive aggregate result into a failure. ### Break it and heal it When the entered apex has no address but its www name does, Heal it offers to look up that www name. This replaces the input and starts a new lookup; it does not add DNS records. The result cards distinguish missing addresses, non-public ranges, incomplete registry attribution and address-family coverage. Different networks are a routing observation, not proof that a CDN is bypassed. The Break it controls create documented edge cases from the visitor's own input or a reserved fixture. They are teaching states, not scans. Heal it restores a safe derived value when the repair is deterministic. Revert remains available when several changes have been made. Use these cases to learn how invalid, missing, mixed or stale evidence appears before diagnosing production. The control never edits DNS, hosting, certificates or provider accounts. ## Worked example The live default is `mozilla.org`. Its apex and www names exercise different route evidence and produce a useful comparison instead of a single provider badge. That observation is time-sensitive; the reason for the default is the shape of the result. Read the example from verdict to Findings, then compare the literal evidence. Open one Break it case and use Heal it or Revert. Finally, replace the default with a domain you are authorised to assess. This sequence demonstrates both the successful path and the failure contract without implying that the named public domain endorses the tool. ## For agents Agents can discover the `website_hosting` operation through Tamperbox MCP. The browser page id `website-hosting` is not the operation name. The server operation and browser renderer can expose different fields; inspect the operation schema before supplying arguments. Preserve the result's distinction between observed evidence, catalog inference and limitation. State whether the run was live or pasted, include the cleaned target and observation time, and never turn “not found” into “does not exist” unless the method truly establishes that condition. Choose a specialist operation when the task is narrow. Use this page's report when its combined view or educational findings add value. Do not pass credentials, private hostnames or customer data into a public lookup. If a repair would change production, present the exact evidence, expected effect, propagation window and rollback before acting. Machine readers should branch on status and structured fields where available, not English punctuation. Treat network and parse errors as inconclusive. Re-run after a meaningful interval rather than repeatedly polling a third-party source. ## Limits IP ownership does not equal hosting responsibility. Anycast, resellers, cloud tenants, reverse proxies and bring-your-own-IP arrangements can obscure the operator. DNS cannot reveal an origin hidden behind a CDN, and two names on one network are not necessarily the same application. All outputs are point-in-time observations. Resolver caching, negative caching, anycast, geo steering, redirects and intermittent upstream failures can change a later run. The service does not retain a monitoring history or notify on change. Local History is an interaction aid, not durable evidence. No result grants permission to probe a target or modify it. Use authorised accounts and owner-approved procedures for deeper checks. Where business, security or legal decisions depend on attribution, obtain confirmation from the responsible provider or domain operator. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034), Domain Names — Concepts and Facilities, especially [section 4.3.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.3.2) for resolver behavior. - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035), Domain Names — Implementation and Specification, especially [section 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1) for resource-record types and classes. - [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110), HTTP Semantics, especially [section 3.7](https://www.rfc-editor.org/rfc/rfc9110#section-3.7) for intermediaries and [section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) for status codes when HTTP evidence is collected. - [Tamperbox Website Hosting Checker](https://tamperbox.dev/website-hosting), the interactive tool and current Markdown mirror. --- # Website Technology Detector How Tamperbox identifies web technologies from bounded HTML and response-header signatures without executing the page. Canonical: https://docs.tamperbox.dev/tools/website-technology/ Updated: 2026-10-25 Applies to: tamperbox.dev, October 2026 Prerequisites: a website hostname or pasted HTML and headers Outputs: technology matches, evidence, categories, version exposure, response facts and limitations Limitations: Public observations are time-sensitive and do not prove ownership, intent or private configuration The tool page is [tamperbox.dev/website-technology](https://tamperbox.dev/website-technology). It opens with a live lookup of `mozilla.org`; replace it to inspect your own target. This guide documents the actual input path, evidence contract, classifications and independent verification steps. <div class="tb-callout"><strong>Where processing happens:</strong> input cleanup, pasted-data parsing and report rendering happen in the browser. Live checks send only the validated public target to the Tamperbox server and the public services required for the lookup. The page stores no report; History is local to the current browser session.</div> ## What the tool answers The checker answers which catalogued web technologies are suggested by the initial HTTPS response and the first bounded portion of its HTML. Its conclusion is deliberately narrower than an ownership or security claim. A displayed provider, product, name or passing check means that the listed public evidence matched a documented rule at the observation time. Every conclusion is paired with evidence. The opening verdict is a summary for orientation, while Findings contains the actionable interpretation and the later result sections retain the underlying records, addresses, fields or names. If a conclusion matters operationally, verify that evidence through an authoritative account or an independent standards-aware client before changing production. ## Inputs ### Accepted source Enter a domain for a live HTTPS fetch, or paste HTML, HTTP headers, or headers followed by a blank line and HTML. Pasted content is inspected locally and scripts are never executed. Input beginning with a JSON object or array produces the informational “Not a web page” result. A live response is bounded to 256 KiB of HTML; later signatures can be missed. Text files are read in the browser. The resulting input follows the same classification rules as the field; reading a file locally does not make a domain or public-IP lookup offline. Cleanup keeps an already accepted record intact and otherwise tries unwrapping a single-line address. Unusable text remains visible for correction. ### When work runs Domain input runs after a 600-millisecond typing pause. Enter runs it immediately; pasted records run immediately. Drops and page-wide paste use the same input loader. Leaving the field applies cleanup and reruns only when cleanup changes the text. Each edit aborts the previous request and increments a generation marker. A slower old response therefore cannot replace a newer result, and clearing the source immediately clears copyable output. The opening input uses the same parser and processing path as a replacement. The labelled live default sends the same requests as another domain. ## Reading the result ### Verdict and privacy The verdict states what the available evidence supports and uses pass, check, fail or informational status consistently. Pass means the bounded rule succeeded. Check means a human should confirm context. Fail means a concrete operational rule was violated. Info describes a limitation, absence or neutral fact and must not be promoted into success or failure by an automated reader. Two privacy lines distinguish browser-only work from live lookup work. The Checked line names the cleaned input and source mode. Copy result is hidden while work is pending, after an error and when input is empty, preventing a stale report from being exported as current. ### Findings and evidence Findings are ordered with failures first, then checks, informational notes and passes. Repeated passing details can fold into a disclosure so that exceptions remain visible. Each item states the observation and its consequence; any remediation is scoped to the evidence rather than presented as a universal configuration recipe. Evidence sections follow Findings and precede History. They are the audit trail for the verdict. A provider label derived from a catalog remains an inference, while a literal record or response field remains an observation. This distinction matters when signatures are incomplete, white-labelled or stale. ### History and handoffs History records intentional input replacements, including Break it examples and their repairs. Revert restores the prior input and runs it again, including live requests when applicable; Reset input returns to the value at the beginning of the recorded sequence. History is not monitoring, persistence or an account log. Check the rest carries the current input to other tools in Domains & hosting. Take it further sends the final hostname to the [CDN and Proxy Detector](https://docs.tamperbox.dev/tools/cdn-detector/) or [Website Hosting Checker](https://docs.tamperbox.dev/tools/website-hosting/). These links appear only when that hostname differs from the input. A receiving tool runs its own check; agreement is not guaranteed. Explicit tool links transfer the input through temporary browser `sessionStorage` and, when needed, a same-origin browser channel. The URL fragment contains a random transfer token, not the input. Transfers are accepted for less than one minute, consumed once, and bound to the destination path. The destination removes the token from its address. Ordinary documentation links and direct visits do not restore a previous input; if transfer storage is unavailable, the link still opens the tool. ## Method ### Validation and collection Before collection, the same domain validation runs in the browser and on the server boundary. Requests are restricted to supported public DNS names and HTTPS roots, redirects are bounded, response sizes are capped and abort signals are propagated. These limits make the observation reproducible and prevent an entered value from becoming an unrestricted network fetch. Use the input modes above to determine which requests run. DNS evidence comes from a public recursive view and can reflect cache state. Local classification cannot add observations absent from the supplied evidence. A server lookup is a fresh observation, not confirmation that cached or pasted evidence is still current. ### Classification rules The server fetches the public HTTPS root with bounded redirects, headers and body size. The detector matches explicit header values, cookie names, generator metadata, script and stylesheet paths, and small HTML signatures. [RFC 9110 section 5](https://www.rfc-editor.org/rfc/rfc9110#section-5) supplies the field parsing model and [RFC 9110 section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) supplies response status meaning. It does not run JavaScript, crawl assets or infer a product merely from generic words. No confidence percentage is invented. When sources disagree, the disagreement is a finding. When a source is unavailable, the affected conclusion becomes informational or inconclusive rather than silently using a previous result. Catalog matches are exact bounded rules; unknown is a valid outcome. ### Ordering and export The renderer calculates all findings from the current observation before updating the verdict, chips, evidence and landing cards. Status priority is fail, check, info, pass. Stable secondary ordering keeps repeated runs readable without changing severity. The Markdown mirror and Copy result output preserve input, summary, findings and important evidence in text form. They do not embed secrets, browser state or the expanded educational cards. Agents should cite the observation time and limitation alongside any exported conclusion. ## Standards and conformance ### Applied specifications | Source | Rule used | Boundary | | --- | --- | --- | | [RFC 9110 section 9.3.1](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.1) | GET retrieves a representation | Only the root representation is requested | | [RFC 9110 section 5](https://www.rfc-editor.org/rfc/rfc9110#section-5) | Field names are case-insensitive metadata | Known field signatures are matched after safe parsing | | [RFC 9110 section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) | Status codes describe the response outcome | Error and challenge pages are explicitly warned | | [HTML Living Standard, metadata](https://html.spec.whatwg.org/multipage/semantics.html#the-meta-element) | meta elements can carry generator information | Generator content is evidence, not an authenticity guarantee | These references define the records and message semantics, not the provider catalogs. A catalog is product logic and can lag branding, acquisitions or custom deployments. Where a standard permits several valid configurations, the tool reports the observed form and avoids declaring one commercial pattern universally correct. ### Where conformance stops The checker is an observer, not an authoritative DNS server, browser, certificate monitor, mail receiver or provider control plane. It does not claim protocol conformance for the target. It applies selected validation and interpretation rules to bounded evidence and exposes the boundary where a fuller protocol operation would begin. The phrase “public” refers to the server's Internet view. Private split-horizon answers, authenticated dashboards and regional routing can differ. Cached answers can remain until TTL expiry, and HTTP intermediaries can transform what the origin sent. ## Finding reference ### Emitted findings | Finding | Severity | Meaning | Repair or next check | | --- | --- | --- | --- | | Technology detected | Pass | A bounded catalog signature matched | Confirm in deployment files or response configuration | | Version announced | Check | Public evidence exposes a product version | Remove the version where practical; patching remains primary | | HTML truncated | Info | Only the first 256 KiB was inspected | Inspect later markup or assets locally | | HTTP error response | Check | Evidence may describe an error or challenge page | Repeat from an authorised path to the normal page | | No HTML inspected | Info | Content-Type was not HTML | Interpret header-only matches narrowly | | Redirect observed | Info | The final host or route differs | Inspect both source and destination | | No known technology | Info | No catalog signature matched | Treat the stack as unknown rather than absent | Wording can include the observed name, count, provider or status. Automated consumers should use the supplied status and evidence rather than parsing the English title as a permanent identifier. A missing finding is not evidence that the corresponding external condition is absent when its source could not be collected. ### Status handling | Status | Consumer action | What not to infer | | --- | --- | --- | | Pass | Preserve the evidence and continue normal review | Permanent correctness, ownership or availability | | Check | Confirm intent and inspect the named evidence | Definite compromise or outage | | Fail | Prioritise the concrete broken rule and verify independently | That every user sees the same failure | | Info | Carry the limitation or neutral fact with the report | Success merely because no failure was emitted | ## Guide ### Verify independently Start with an authoritative or widely used command-line client. For DNS, use `dig` with the exact record type and compare every returned owner, target and TTL. Add `+trace` only when delegation matters; a trace and a recursive answer solve different questions. For HTTPS, use `curl -I --location https://host/` and retain each hop and response field. For certificates, use an established TLS client and a CT monitor you trust. Repeat from another network when geography or split routing could matter. Save the observation time and the original evidence before editing. After a DNS change, wait at least the prior TTL and then query both the intended authorities and independent recursive resolvers. ### Repair safely Do not delete an unfamiliar record or reroute a public name merely because a catalog labels it. First identify the owning service, deployment repository or provider account. Confirm whether the item is current, a migration remnant, a failover path or a delegated responsibility. Make the smallest reversible change, keep the prior value, and have a rollback trigger. Re-run this page after propagation, then verify the user-visible service. A clean public lookup cannot prove application health. Conversely, an informational unknown does not require a speculative change. ### Diagnose conflicting evidence When two signals disagree, ask whether they describe different layers: apex versus www, resolver cache versus authority, CDN edge versus origin, entered host versus redirected host, or certificate history versus current DNS. Compare literal evidence before comparing labels. The disagreement itself often reveals a migration or intermediary. If a lookup fails, preserve the error and retry once. Repeated timeouts are not equivalent to empty data. Use the specialist tool linked by the finding for deeper parsing rather than converting an inconclusive aggregate result into a failure. ### Break it and heal it Break it uses the pasted source or the response captured by the last successful lookup: it can add illustrative version headers, keep only the existing headers, or create a labelled error-response example. Heal it can remove announced version numbers from response headers or preview an HSTS header locally. It never rewrites versioned script URLs, deploys configuration or changes the live site. The HSTS preview omits includeSubDomains; review HTTPS readiness and policy before publishing any header. Lookup failures and JSON input do not offer these repairs. The Break it controls create documented edge cases from the visitor's own input or a reserved fixture. They are teaching states, not scans. Heal it restores a safe derived value when the repair is deterministic. Revert remains available when several changes have been made. Use these cases to learn how invalid, missing, mixed or stale evidence appears before diagnosing production. The control never edits DNS, hosting, certificates or provider accounts. ## Worked example The live default is `mozilla.org`. It fills several technology categories from inspectable evidence and demonstrates the final-host response facts. The names and versions remain live observations and are not embedded as permanent claims. Read the example from verdict to Findings, then compare the literal evidence. Open one Break it case and use Heal it or Revert. Finally, replace the default with a domain you are authorised to assess. This sequence demonstrates both the successful path and the failure contract without implying that the named public domain endorses the tool. ## For agents Agents can discover the `website_technology` operation through Tamperbox MCP. The browser page id `website-technology` is not the operation name. The server operation and browser renderer can expose different fields; inspect the operation schema before supplying arguments. Preserve the result's distinction between observed evidence, catalog inference and limitation. State whether the run was live or pasted, include the cleaned target and observation time, and never turn “not found” into “does not exist” unless the method truly establishes that condition. Choose a specialist operation when the task is narrow. Use this page's report when its combined view or educational findings add value. Do not pass credentials, private hostnames or customer data into a public lookup. If a repair would change production, present the exact evidence, expected effect, propagation window and rollback before acting. Machine readers should branch on status and structured fields where available, not English punctuation. Treat network and parse errors as inconclusive. Re-run after a meaningful interval rather than repeatedly polling a third-party source. ## Limits Signature detection has false positives and false negatives. Reverse proxies can add headers, build tools can leave stale metadata, products can remove branding, and client-side code can load after the bounded response. The checker does not execute scripts, authenticate, scan dependencies, test vulnerabilities or establish who operates a detected product. All outputs are point-in-time observations. Resolver caching, negative caching, anycast, geo steering, redirects and intermittent upstream failures can change a later run. The service does not retain a monitoring history or notify on change. Local History is an interaction aid, not durable evidence. No result grants permission to probe a target or modify it. Use authorised accounts and owner-approved procedures for deeper checks. Where business, security or legal decisions depend on attribution, obtain confirmation from the responsible provider or domain operator. ## References - [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034), Domain Names — Concepts and Facilities, especially [section 4.3.2](https://www.rfc-editor.org/rfc/rfc1034#section-4.3.2) for resolver behavior. - [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035), Domain Names — Implementation and Specification, especially [section 3.2.1](https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1) for resource-record types and classes. - [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110), HTTP Semantics, especially [section 3.7](https://www.rfc-editor.org/rfc/rfc9110#section-3.7) for intermediaries and [section 15](https://www.rfc-editor.org/rfc/rfc9110#section-15) for status codes when HTTP evidence is collected. - [Tamperbox Website Technology Detector](https://tamperbox.dev/website-technology), the interactive tool and current Markdown mirror. --- # What Is My IP Address? How the What Is My IP page reads the public address your connection uses, why one connection shows only IPv4 or IPv6, how the device test checks both families, and how to read and act on each result. Canonical: https://docs.tamperbox.dev/tools/what-is-my-ip/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A browser on the connection to identify; the device test needs the browser to reach api.ipify.org and api6.ipify.org Outputs: The public address and its family, the network, AS number and estimated country, and after the device test the IPv4 and IPv6 address the device reaches the internet with Limitations: Describes one connection; a VPN, proxy or private relay replaces the address; the country is an estimate for the network; a failed IPv6 request is inconclusive The tool page is [tamperbox.dev/what-is-my-ip](https://tamperbox.dev/what-is-my-ip). It has no input box: opening it reads your connection and shows the address in large type, with the network it belongs to, and a device test checks IPv4 and IPv6 separately. This page is the long version: where each value comes from, why the page never shows a sample address, how the device test works, and how to use the result for an allowlist or a support ticket. <div class="tb-callout"><strong>Where processing happens:</strong> opening the page sends one request to the Tamperbox server, which reads the address your browser connected from and the network metadata of that connection, returns that observation. The device test runs only when you press it: your browser sends two requests to the public echo service ipify, one over IPv4 and one over IPv6, without cookies or a referrer. Nothing else is sent, and the address is never passed to advertisers.</div> ## What the tool answers 1. **What address does the internet see for me?** The source address of this connection. 2. **Is it IPv4 or IPv6?** The family this connection used. 3. **Whose network is it?** The organisation, AS number and estimated country from the connection's metadata. 4. **Does the other family work too?** After the device test: whether this device also reaches the internet over IPv4 and over IPv6, and with which address. ## Inputs There is nothing to type. The page reads the connection it was loaded over. Check again repeats the read, which is useful after switching a VPN on or off, or moving between Wi-Fi and mobile data. Arriving from another tool with a value does not change anything: the address is always read, never taken from the page. The page never shows a sample address. A made-up address on a "what is my IP" page could be copied into a firewall rule; if the read fails, the page says "Unavailable" and the device test still works without our server. ## Reading the result ### Your public IP address The address in large type, with Copy address, and a line naming the network and country. The label says the family: "Your public IPv4 address" or "Your public IPv6 address". ### Verdict and chips | Verdict | When | | --- | --- | | Connected over IPv4 | The connection used IPv4 and the device test has not run | | Connected over IPv6 | The connection used IPv6 | | IPv6 works too | The connection used IPv4 and the device test reached the internet over IPv6 | | Connected over IPv4. No IPv6 found from this device | The IPv6-only request did not complete (a warning) | | Your address could not be read | The server read failed | The chips say which families work, and "IPv6 not tested" until the device test runs. ### Findings The caveats for this connection, worst first; see the [Finding reference](#finding-reference). ### IPv4 and IPv6 Two lanes, one per family: Works (with the address), Not found, or Not tested, and the device test button with the hosts it contacts. ### Your network Network name, autonomous system and country, with a link to the full connection details. ### Take it further These links carry values derived from the current result. A link is absent when its required evidence is missing; the tool does not invent a target. | Destination | Value and condition | | --- | --- | | [ASN Lookup](https://docs.tamperbox.dev/tools/asn-lookup/) | The public address reported for this connection | | [Reverse DNS](https://docs.tamperbox.dev/tools/reverse-dns/) | The same observed address | | [BGP Route Lookup](https://docs.tamperbox.dev/tools/bgp-lookup/) | The same observed address | | [ASN Lookup for IPv6](https://docs.tamperbox.dev/tools/asn-lookup/) | The device test's IPv6 address, when the page connection used IPv4 and the IPv6 test succeeded | Check the rest opens sibling pages without carrying the address. Take it further is the explicit address transfer. These pages have no editable source, Break it, Heal it or input History; Check again refreshes the connection reading. ### What this result means Six cards explain the current findings: Ask your agent, In plain words, What does it mean?, What good looks like, How to fix it, and Tool limitations. Expand a card to read the explanation and its method or guide link. Copying an agent prompt does not run another check. The cards interpret the evidence already shown; they are not an additional measurement or an independent confirmation. If the connection reading fails or no result is available, result-specific cards clear and contextual links disappear. Read the verdict before relying on a card, and distinguish a missing observation from a confirmed negative result. ## Method ### 1. Reading the connection The server takes the address from the `CF-Connecting-IP` header set by Cloudflare's edge for every request, not from any header the browser can set. When the edge replaced an IPv6 address with a pseudo IPv4 address (one from 240.0.0.0/4), the real IPv6 address from `CF-Connecting-IPv6` is used instead. The family is that address's version. The network name, AS number and country come from the edge's connection metadata (`request.cf.asOrganization`, `asn` and `country`); they describe the network the address belongs to, not the person. No other header is consulted, so a forwarded-for header cannot change the answer. ### 2. Why one connection shows one family A browser opens each connection over one family. With both available, most clients prefer IPv6 and fall back to IPv4 quickly when IPv6 is slow ("Happy Eyeballs", [RFC 8305, section 5](https://www.rfc-editor.org/rfc/rfc8305#section-5)). So a page reached over IPv4 cannot tell whether IPv6 works, and the server answer says so: an IPv4 request returns "not tested", never "IPv6 unavailable". ### 3. The device test Pressing the test makes two requests from your browser at the same time: `https://api.ipify.org?format=json`, which answers over IPv4 only, and `https://api6.ipify.org?format=json`, which answers over IPv6 only. Each has a 5 second limit, sends no cookies and no referrer, and must return a small JSON body (at most 1 KiB) whose address is of the expected family. A request that fails, times out, is blocked or returns the other family counts as "inconclusive", not "missing": a content blocker, a DNS filter, a firewall or an outage of the echo service all look the same. The test runs in the browser on purpose: a server-side request would test the server's connectivity, not yours. ### 4. Findings | Rule | Condition | Finding | | --- | --- | --- | | No IPv6 | The connection used IPv4 and the IPv6-only request did not complete | CHECK | | Two addresses | The connection used IPv4 and the IPv6-only request returned an address | INFO | | IPv6 rotates | The connection used IPv6 | INFO | | VPN or proxy | An address was read | INFO | The rotation note follows [RFC 8981](https://www.rfc-editor.org/rfc/rfc8981): devices form temporary addresses ([section 3.4](https://www.rfc-editor.org/rfc/rfc8981#section-3.4)) with a default preferred lifetime of one day and a valid lifetime of two ([section 3.8](https://www.rfc-editor.org/rfc/rfc8981#section-3.8)), so the address a site sees changes about daily while the provider may also change the delegated prefix. <span id="standards"></span> ## Standards and conformance | Specification | Sections used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 4291](https://www.rfc-editor.org/rfc/rfc4291) IPv6 addressing | [2.5.4](https://www.rfc-editor.org/rfc/rfc4291#section-2.5.4) | Addresses are shown in their canonical compressed form | The page does not split prefix and interface ID | | [RFC 8981](https://www.rfc-editor.org/rfc/rfc8981) temporary addresses | [3.4](https://www.rfc-editor.org/rfc/rfc8981#section-3.4), [3.8](https://www.rfc-editor.org/rfc/rfc8981#section-3.8) | Explains why an IPv6 address changes | Obsoletes [RFC 4941](https://www.rfc-editor.org/rfc/rfc4941) | | [RFC 8305](https://www.rfc-editor.org/rfc/rfc8305) Happy Eyeballs v2 | [5](https://www.rfc-editor.org/rfc/rfc8305#section-5) | Explains why one connection shows one family | | | [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598) shared address space | [4](https://www.rfc-editor.org/rfc/rfc6598#section-4) | Background for carrier-grade NAT: the address shown is the provider's gateway | The page cannot see your router's WAN address | | [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918#section-3) private addresses | 3 | Your device's address at home is private and never shown here | | ## Finding reference | Finding | Severity | What it means for you | Fix | | --- | --- | --- | --- | | No IPv6 from this device | CHECK | The IPv6-only request failed; other destinations or routes may still work | Enable IPv6 in the router; ask the provider; test without blockers | | This device has two public addresses | INFO | Logs and allowlists may show either | Account for both families under your access policy | | Your IPv6 address may change | INFO | Temporary addresses rotate about daily | Confirm the assigned prefix and authorize only the intended scope | | A VPN or proxy changes this address | INFO | The address shown may be the exit of a tunnel | Check again with it off to compare | ## Guide ### Adding your connection to a firewall allowlist 1. Read the address and its family here. 2. For IPv4, allowlist the address; ask your provider whether it is static, because many home addresses change after a router restart. 3. For IPv6, confirm the assigned prefix and its stability with your network administrator. Do not infer authorization scope from four printed groups: compressed notation can omit groups, and permitting a /64 permits many devices. Use the narrowest scope that meets the access policy. 4. Run the device test and account for both families if the destination uses both, subject to the same access policy. ### Giving your address to support Copy address puts it on the clipboard. Mention the time and whether a VPN was on: an address is only meaningful together with when it was used. ### IPv6 missing Look for IPv6 in the router's WAN or internet settings (often "IPv6", "DHCPv6" or "prefix delegation"), and ask your provider whether your plan includes it. Then run the device test again. ### Reading the network row The network row names the organisation that announces your address (your provider, a mobile operator, a VPN company or a cloud provider), its autonomous system number, and the country the edge associates with the connection. A VPN or private relay shows the relay operator here, which can help compare before and after an intended network change but does not prove that every application uses the tunnel. A mobile connection often shows a country or city far from you, because mobile operators route traffic through a few central gateways. None of these values locates a household: the provider holds the mapping from address to customer and its subscriber records are not part of this tool. ### Why the address is shared Your devices at home have private addresses ([RFC 1918, section 3](https://www.rfc-editor.org/rfc/rfc1918#section-3)), such as 192.168.1.20, that never appear on the internet. The router translates them to its one public address, so every phone and laptop at home shows the same address here. Some providers add a second translation, carrier-grade NAT, and many customers then share one public address; your router's own WAN address is then in 100.64.0.0/10 ([RFC 6598, section 4](https://www.rfc-editor.org/rfc/rfc6598#section-4)) and differs from the address on this page. With IPv6 there is usually no translation: each device has its own global address within the prefix your provider delegates, which is why the IPv6 lane can show an address no other device at home uses. ### Confirm without Tamperbox ```sh curl -4 https://api.ipify.org curl -6 https://api6.ipify.org ``` The first prints your IPv4 address, the second your IPv6 address or an error if that request cannot complete. ## Worked example On a typical home connection over IPv4, the page shows the router's public address with the provider's name and country, the verdict "Connected over IPv4", and "IPv6 not tested". Pressing the device test sends the two echo requests. If the IPv6 request returns an address, the verdict becomes "IPv6 works too", both lanes read Works, and a finding notes that the device has two public addresses. If it fails, the verdict warns that no IPv6 was found, and the findings lists the router and provider steps. This page never shows a sample address, so there is no fixed example to describe. ## For agents Through the Tamperbox MCP server, `what_is_my_ip` describes the connection of whatever calls it: the agent's outbound service or gateway, not the person using the agent. The result carries that warning. Use it to learn the request source seen by the service, never to answer "what is my IP" for a user; send the user to the page instead. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) and [Security and privacy](https://docs.tamperbox.dev/reference/security/). [ASN Lookup](https://docs.tamperbox.dev/tools/asn-lookup/) explains the network behind an address. ### Transfers to another tool Explicit sibling-tool controls can carry the current input or observed address to another page. The shared navigation stores that value temporarily in tab-scoped `sessionStorage`, accepts a transfer for at most one minute, and puts a random transfer token in the URL fragment. The input itself is not placed in the URL. The receiving page consumes the transfer and applies its own input rules; tools with a manual Run button still require that action for live checks. This is not a saved result, and the destination can send the value to the services it needs. Ordinary edits and lookups do not create a durable report archive. ## Limits - One connection, at one moment; Check again after any network change. - A VPN, proxy or private relay is shown in place of your connection. - The country is an estimate for the network. - A failed device test is inconclusive. - The address is shown to you and not stored. ## References - [RFC 4291](https://www.rfc-editor.org/rfc/rfc4291), IP Version 6 Addressing Architecture: section 2.5.4. - [RFC 8981](https://www.rfc-editor.org/rfc/rfc8981), Temporary Address Extensions for Stateless Address Autoconfiguration in IPv6: sections 3.4 and 3.8. Obsoletes [RFC 4941](https://www.rfc-editor.org/rfc/rfc4941). - [RFC 8305](https://www.rfc-editor.org/rfc/rfc8305), Happy Eyeballs Version 2: section 5. - [RFC 6598](https://www.rfc-editor.org/rfc/rfc6598), IANA-Reserved IPv4 Prefix for Shared Address Space: section 4. - [RFC 1918](https://www.rfc-editor.org/rfc/rfc1918), Address Allocation for Private Internets: section 3. --- # WHOIS & RDAP Lookup How the WHOIS & RDAP Lookup finds the registry for a domain or IP address, reads its RDAP record into the registrar, dates, status codes, nameservers, DNSSEC data and abuse contact, and what each finding means. Canonical: https://docs.tamperbox.dev/tools/whois-lookup/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A domain, an IPv4 or IPv6 address, or an RDAP record saved as JSON Outputs: The registration as rows, status codes in plain words, nameservers and DNSSEC data, registry events, the raw RDAP JSON, findings worst first, and the underlying registry record Limitations: One registry record at one moment; registrant details are usually redacted; an IP record names who holds the block, not who runs the server; port 43 WHOIS is not queried The tool page is [tamperbox.dev/whois-lookup](https://tamperbox.dev/whois-lookup). It opens with a live lookup of `tamperbox.dev` and takes a domain, an IP address, or a saved RDAP record. This page is the long version: how the registry is found, what each part of the record means, every finding, and what to do with what you learn. <div class="tb-callout"><strong>Where processing happens:</strong> a domain or address is sent to the Tamperbox server, which finds the responsible registry in the IANA bootstrap lists, asks its RDAP service and returns the record unchanged. The record is read in your browser. Pasted RDAP JSON never leaves the browser. History stays in memory in the open page. Explicit links to another tool may temporarily keep a one-use transfer in browser session storage; transfers expire after one minute and do not put the input in the URL.</div> ## What the tool answers For a domain: 1. **Who is it registered with, and since when?** Registrar, IANA registrar ID, registration, expiry and last-change dates. 2. **Who owns it?** The registrant, or that the details are redacted. 3. **How is it protected?** Status codes: locks, holds, grace periods. 4. **Where is its DNS, and is the delegation signed?** Nameservers with their provider, and the DS records the registry holds. 5. **What happened to it?** The registry's events, oldest first. 6. **Where do abuse reports go?** The registrar's abuse email and phone. For an IP address: the network block it belongs to, its range and CIDR, the organisation holding it, its type and parent, the abuse contact, and the registry's remarks. WHOIS over port 43 is not used: RDAP is its successor, with structured data and a standard way to find the right server. ICANN requires gTLD registries and registrars to run RDAP. ## Inputs ### A domain `example.com`, looked up when you stop typing (or at once on Enter). A pasted address is reduced to what the tool takes: `https://www.example.com/page` becomes `www.example.com`, an email address its domain, quotes and brackets are dropped. Text that contains nothing usable stays as pasted with an explanation. Typing is never rewritten mid-word, and Break it loads are never cleaned. Registries hold records for registered names only. `www.example.com` usually has no record even when `example.com` does; enter the registered domain yourself when a subdomain has no record. ### An IP address IPv4 or IPv6, looked up at the regional internet registry that holds the block. Private and other non-public addresses are refused: "Enter a public IP address." ### RDAP JSON A domain or IP network record saved from an RDAP service (it starts with `{`), pasted or dropped as a file up to 256 KiB, read in the browser. Text that is not JSON gives "Not readable JSON"; JSON that is not a domain or IP network object is refused. ## Reading the result ### Verdict and chips For a domain: "Registered with *registrar*", with the year of registration and the expiry date, at FAIL, CHECK or PASS by the worst finding, and a line saying when the registrant details are redacted. The chips give the expiry, the transfer lock and DNSSEC. For an IP address: the network's name and who it is registered to. For no record: "Not registered: the registry has no record of …". ### Findings The registration checks appear worst first, with passing checks folded when there are several. The count reports problems and things to check, or "No problems". An IP record adds an INFO finding naming its holder, network and any abuse contact; a missing record adds "No registration record" (INFO). The [finding reference](#finding-reference) lists them all. ### Registration The record as rows. For a domain: domain and registry handle, registrar and IANA ID, registered, expires (red when past), last changed, registrant (or "Redacted for privacy"), abuse contact. For a network: address, network name and handle, range and CIDR, organisation and country, type and parent, abuse contact. ### Status codes, nameservers and DNSSEC, registry events Status codes are listed with their plain names, meaning and weight (the table is in the [Domain Availability method](https://docs.tamperbox.dev/tools/domain-availability/#4-status-codes)). Nameservers are listed with the DNS provider they belong to; DS records follow with their key tag, algorithm and digest type, or "No DS record" when the delegation is unsigned. Registry events (registered, expires, last changed, transferred, locked, the registry's own refresh) are listed oldest first; future events are marked. ### The RDAP record The registry's parsed JSON, formatted with indentation, with a Copy button: the source for anything the rows leave out (remarks, notices, links, extensions). ### History and next checks History appears below the result evidence after Break it or Heal it changes the input. Revert restores the input before the latest recorded change; Reset input returns to the input before the first recorded change. Typing or pasting a new input starts a new history. Restoring a live input runs the lookup again, rather than restoring a saved response. Take it further offers a domain expiry as a Unix timestamp, a DNSSEC check when the registry reports a signed delegation, or the first returned network CIDR for a BGP lookup. For a longer name with no record, Heal it may suggest the name one label up; that suggestion does not establish the registrable domain. ## Method ### 1. Finding the registry The server reads the IANA RDAP bootstrap file that matches the input: domain names, IPv4 or IPv6 ([RFC 9224, sections 4 and 5](https://www.rfc-editor.org/rfc/rfc9224#section-4)). Domains match the longest registered ending; addresses match the longest covering prefix. Only HTTPS services are used, and the query is `domain/<name>` or `ip/<address>` ([RFC 9082, sections 3.1.1 and 3.1.3](https://www.rfc-editor.org/rfc/rfc9082#section-3.1.1)). Up to three redirects are followed, each checked to be a public HTTPS address; regional registries often redirect an address to the registry that actually holds it. With no service for the ending, the page says so and that this "does not mean it is available". ### 2. Not found [RFC 7480, section 5.3](https://www.rfc-editor.org/rfc/rfc7480#section-5.3): an empty result is a 404, and the body is optional. A 404 counts as "no record" only with RDAP evidence: an error document with `errorCode` 404, or an empty body served as RDAP or JSON. An empty-body result requires a successful read and a JSON or RDAP JSON media type, optionally with parameters. Failed body reads and HTML 404 responses do not establish that a record is missing. A record whose `objectClassName` is not the one asked for is refused. ### 3. Reading a domain record From the domain object ([RFC 9083, section 5.3](https://www.rfc-editor.org/rfc/rfc9083#section-5.3)): - **Name and handle**: `ldhName` (or `unicodeName`) and `handle`. - **Registrar**: the entity with the `registrar` role, its `fn`, and the public ID of type "IANA Registrar ID" ([section 4.8](https://www.rfc-editor.org/rfc/rfc9083#section-4.8)); the abuse contact is the registrar's child entity with the `abuse` role (email and telephone). - **Registrant**: the entity with the `registrant` role (name, organisation, country), or "Redacted for privacy" when a description in the record's `redacted` list ([RFC 9537](https://www.rfc-editor.org/rfc/rfc9537)) names registrant fields. - **Dates**: the `registration`, `expiration` and `last changed` events ([section 4.5](https://www.rfc-editor.org/rfc/rfc9083#section-4.5)); every event is listed in the timeline. - **Status**: the `status` array ([section 4.6](https://www.rfc-editor.org/rfc/rfc9083#section-4.6)), EPP values of [RFC 5731, section 2.3](https://www.rfc-editor.org/rfc/rfc5731#section-2.3) and [RFC 3915, section 3.1](https://www.rfc-editor.org/rfc/rfc3915#section-3.1) in their RDAP spelling ([RFC 8056, section 2](https://www.rfc-editor.org/rfc/rfc8056#section-2)). - **Nameservers** and **DNSSEC**: `nameservers[].ldhName`, and `secureDNS.delegationSigned` with `dsData` (key tag, algorithm, digest type, digest). ### 4. Registration checks The same lifecycle checks as the [Domain Availability Checker](https://docs.tamperbox.dev/tools/domain-availability/#5-lifecycle-checks): expiry passed, within 30 days, or later; holds; a missing transfer lock; the registry lock; an unsigned delegation. The verdict takes the level of the worst check. Expiry findings use rounded whole days; date fields compare timestamps directly, so the two can differ close to a day boundary. ### 5. Reading an IP network record From the IP network object ([RFC 9083, section 5.4](https://www.rfc-editor.org/rfc/rfc9083#section-5.4)): `name`, `handle`, `startAddress` and `endAddress`, the `cidr0_cidrs` extension for the CIDR, `type`, `country`, `parentHandle`, the registrant's `fn`, the first abuse contact found among the entities and their children, and the remarks. No checks are applied: the record describes who holds the block. ## Standards and conformance | Specification | Sections used | How the tool applies them | Where it stops | | --- | --- | --- | --- | | [RFC 7480](https://www.rfc-editor.org/rfc/rfc7480), HTTP usage | [5.3](https://www.rfc-editor.org/rfc/rfc7480#section-5.3) | 404 with RDAP evidence means no record | HTML 404s are treated as inconclusive | | [RFC 9082](https://www.rfc-editor.org/rfc/rfc9082) (obsoletes RFC 7482) | [3.1.1](https://www.rfc-editor.org/rfc/rfc9082#section-3.1.1), [3.1.3](https://www.rfc-editor.org/rfc/rfc9082#section-3.1.3) | Exact domain and IP lookups | No searches, no entity or AS lookups (the ASN lookup covers AS numbers) | | [RFC 9083](https://www.rfc-editor.org/rfc/rfc9083) (obsoletes RFC 7483) | 4.5, 4.6, 4.8, 5.3, 5.4 | Fields read into rows; raw JSON shown | Notices, remarks on domains and vCard fields beyond those listed stay in the raw JSON | | [RFC 9224](https://www.rfc-editor.org/rfc/rfc9224) (obsoletes RFC 7484) | 4, 5.1, 5.2 | Longest-match bootstrap, HTTPS only | | | [RFC 9537](https://www.rfc-editor.org/rfc/rfc9537), redaction | The `redacted` member | Registrant shown as redacted when the list names it | Other redacted fields are visible in the raw JSON | | [RFC 5731](https://www.rfc-editor.org/rfc/rfc5731), [RFC 3915](https://www.rfc-editor.org/rfc/rfc3915), [RFC 8056](https://www.rfc-editor.org/rfc/rfc8056) | Status values and mapping | Plain names and weights | | ## Finding reference | Finding | Level | Source | Meaning | What to do | | --- | --- | --- | --- | --- | | Expires in N days (more than 30) | PASS | [RFC 9083 4.5](https://www.rfc-editor.org/rfc/rfc9083#section-4.5) | Paid up | | | Expires in N days (30 or fewer) | CHECK | | Lapses soon without renewal | Check auto-renew and payment | | Expired N days ago | FAIL | | Past the reported expiry; renewal rights depend on policy | Renew | | Expired and on its way out | FAIL | [RFC 3915 3.1](https://www.rfc-editor.org/rfc/rfc3915#section-3.1) | Redemption or pending delete | Restore now, or follow its release | | On hold | FAIL | [RFC 5731 2.3](https://www.rfc-editor.org/rfc/rfc5731#section-2.3) | Does not resolve | Ask the registrar why | | No transfer lock | CHECK | [RFC 5731 2.3](https://www.rfc-editor.org/rfc/rfc5731#section-2.3) | Can be moved with its auth code | Turn the lock on | | Registry lock | PASS | [RFC 5731 2.3](https://www.rfc-editor.org/rfc/rfc5731#section-2.3) | Server transfer and update restrictions are present; process is registry-specific | | | Delegation not signed | INFO | [RFC 9083 5.3](https://www.rfc-editor.org/rfc/rfc9083#section-5.3) | No DS at the registry | See the [DNSSEC Checker](https://docs.tamperbox.dev/tools/dnssec-checker/) | | No registration record (finding); Not registered (verdict) | INFO | [RFC 7480 5.3](https://www.rfc-editor.org/rfc/rfc7480#section-5.3) | No record for this exact name | Check the registered name | | Registered to *holder* (IP finding and verdict) | INFO | [RFC 9083 5.4](https://www.rfc-editor.org/rfc/rfc9083#section-5.4) | Who holds the block | Report abuse to its contact | ## Guide ### Contacting a domain's owner Most records redact the registrant. Contact the registrar named in the record: registrars offer a contact form or relay address for the owner, and handle abuse reports at the abuse contact shown. For a legal request, the registrar's terms say how to request disclosure. ### Reporting abuse For a phishing or malware domain, write to the registrar's abuse contact with the full URL, the time you saw it and the evidence. For spam or attacks from an address, look the address up here and write to the network's abuse contact with the address, the exact times (with time zone) and the headers or logs. ### Moving a domain to another registrar Remove the transfer lock at the current registrar, get the auth code, start the transfer at the new registrar, and confirm it by email. Note any "Just transferred" status afterwards: a further transfer is usually blocked for 60 days. Turn the lock back on once the transfer completes. ### Independent check ```sh # RDAP for a domain or an address, through a public redirector that uses the IANA bootstrap curl -sL https://rdap.org/domain/example.com | head -c 600 curl -sL https://rdap.org/ip/198.51.100.24 | head -c 600 # Classic port 43 WHOIS, where the registry still runs it whois example.com ``` ### Break it cases Every case is a sample record on the reserved `.example` zone or a documentation address: a registration's state belongs to the world, not to your input. | Case | Input | What it shows | | --- | --- | --- | | An IP address | `198.51.100.24` | An IP network record: TEST-NET-2, reserved for documentation | | Not registered | `harborsupply-marine.example` | No registration record | | Expired, redeemable | `anchor-chandlery.example` | Expired and on its way out, with no nameservers | | No transfer lock | `dockside-tools.example` | A registration without a transfer lock | ## Worked example The page opens with a live RDAP lookup of `tamperbox.dev`. Start with the registrar and dates, then read the status, nameserver and DNSSEC sections. Finally inspect the JSON for notices or extensions that the summary does not render. The registry can change these fields, so this guide does not promise a fixed registrar, expiration date or nameserver set. A missing registrant name is not evidence that the domain has no owner. Redaction, omitted fields and privacy placeholders require careful interpretation. Likewise, the registry's signed-delegation flag and DS data describe registration-side information; use the DNSSEC Checker to inspect the public chain rather than treating the flag as a validation result. Choose An IP address in Break it to view the reserved documentation-network fixture. The network range, holder and abuse contact answer a different question from a domain registration. An allocation does not identify the operator of every server in that range. Heal it restores the prior input, and live inputs are queried again. ## For agents Search the Tamperbox MCP catalog for `whois_lookup`, inspect its schema and supply the domain or public IP as `q`. It returns the RDAP object from the lookup service, not the browser's formatted rows or lifecycle findings. Preserve notices, redactions and missing fields when summarizing it. A failed lookup must not become an assertion that the name is available. Keep these warnings with any conclusion: - One registry record at one moment; registrars may hold more than the registry shows. - Redacted registrant data is not evidence about the owner. - An IP record names who holds the block, not who operates the server. See [Connect an MCP client](https://docs.tamperbox.dev/mcp/connect/) for the calling pattern and [Security and privacy](https://docs.tamperbox.dev/reference/security/) for where the input travels. ### Keeping an observation reproducible Record the target, the time of the lookup, the relevant raw records and the resolver or registry that supplied them. Repeat a live lookup after a configuration change instead of assuming a restored input restores an old response. A saved RDAP object or pasted DNSSEC record set is a snapshot: its dates are assessed against the current clock, but its contents are not refreshed. Separate absence from failure. A successful response with no applicable record, a rejected input, a timeout and an upstream error support different conclusions. Preserve an error when a query could not complete; do not replace it with a claim that the record does not exist. When sharing findings, include the narrow observation and the relevant limitation rather than only the verdict label. ## Limits - One registry record, at one moment. - Registrant details are usually redacted. - Port 43 WHOIS is not queried; endings without RDAP cannot be looked up. - An IP record says who holds the block, not who runs the server. - The Break it cases use sample records and documentation addresses. - History stays in memory in the open page. Explicit links to another tool may temporarily keep a one-use transfer in browser session storage; transfers expire after one minute and do not put the input in the URL. ## References - [RFC 3915, Domain Registry Grace Period Mapping for EPP](https://www.rfc-editor.org/rfc/rfc3915), section 3.1 - [RFC 5731, EPP Domain Name Mapping](https://www.rfc-editor.org/rfc/rfc5731), section 2.3 - [RFC 7480, HTTP Usage in RDAP](https://www.rfc-editor.org/rfc/rfc7480), section 5.3 - [RFC 8056, EPP and RDAP Status Mapping](https://www.rfc-editor.org/rfc/rfc8056), section 2 - [RFC 9082, RDAP Query Format](https://www.rfc-editor.org/rfc/rfc9082), sections 3.1.1 and 3.1.3 (obsoletes RFC 7482) - [RFC 9083, JSON Responses for RDAP](https://www.rfc-editor.org/rfc/rfc9083), sections 4.5, 4.6, 4.8, 5.3 and 5.4 (obsoletes RFC 7483) - [RFC 9224, Finding the Authoritative RDAP Service](https://www.rfc-editor.org/rfc/rfc9224), sections 4 and 5 (obsoletes RFC 7484) - [RFC 9537, Redacted Fields in RDAP](https://www.rfc-editor.org/rfc/rfc9537) --- # Workflow patterns Reusable patterns for transforms, diagnostics, comparisons, and evidence-preserving handoffs. Canonical: https://docs.tamperbox.dev/workflows/ Updated: 2026-10-19 Applies to: MCP 0.2.0 Prerequisites: A connected Tamperbox MCP server Outputs: A focused result with warnings and provenance Limitations: Workflow composition does not expand the operation catalog or bypass service limits. ## Discover, then call Start every unfamiliar task with `search`. Select the smallest set of operations that can answer the question. Inspect their schemas before constructing inputs. ## Transform an artifact Transforms accept a text artifact shaped as `{ mediaType, value }`. The `value` remains text even when it contains serialized JSON. 1. Search for the transform operation. 2. Build the exact input artifact. 3. Run the operation with `execute`. 4. Parse the output only if the next step needs an object. ## Combine independent diagnostics Independent public checks can run in parallel within the execution concurrency limit. Keep each result under a descriptive key and retain operation-specific warnings. ```js const [dns, headers] = await Promise.all([ tamperbox.request({ method: 'POST', path: '/v1/tools/dns_lookup', body: { name: 'example.com', type: 'A', resolver: 'google' }, }), tamperbox.request({ method: 'POST', path: '/v1/tools/security_headers', body: { url: 'https://example.com/' }, }), ]); return { dns, headers }; ``` ## Chain compatible artifacts An operation can feed another when the first output matches the next input contract. A common example decodes a synthetic JWT, then passes its JSON artifact into `json_to_yaml`. Keep the first operation's warning. Decoding still does not verify the signature, issuer, audience, expiry, or trust. ## Report unavailable evidence If a probe is partial or unavailable, state what is missing. Do not substitute an invented grade, address, record, or successful check. --- # YAML to JSON Converter How Tamperbox converts JSON-compatible YAML to JSON live in the browser, exposes presentation loss, and refuses ambiguous aliases, keys and numbers. Canonical: https://docs.tamperbox.dev/tools/yaml-to-json/ Updated: 2026-10-24 Applies to: tamperbox.dev, October 2026 Prerequisites: A YAML value pasted, typed, dropped or opened as a local file Outputs: Pretty-printed JSON representing the resolved JSON-compatible YAML values; Findings for validity, presentation loss and interoperability boundaries Limitations: Comments, custom tags, anchor names, aliases, scalar spelling and formatting are not preserved; The converter accepts the JSON-compatible YAML schema, not every YAML 1.1 or application-specific feature; Input is limited to 1,000,000 characters, 80 levels, 100 aliases and 100,000 values The tool page is [tamperbox.dev/yaml-to-json](https://tamperbox.dev/yaml-to-json). It opens with a synthetic QA test suite, resolves it under a deliberately narrow YAML schema and rewrites JSON as the source changes. This guide defines which YAML is accepted, which presentation is lost, every refusal and how to prove that the resulting JSON still carries the intended test data. <div class="tb-callout"><strong>Where processing happens:</strong> the YAML is sent only to a Web Worker in the current browser tab. Conversion does not upload the source or evaluate it as code. Explicit reverse-conversion navigation temporarily stores the output in tab-scoped session storage for the handoff; ordinary conversion does not persist it. Custom YAML tags are rejected rather than constructed.</div> ## What the tool answers The page answers whether the source is valid JSON-compatible YAML, whether its resolved representation fits the JSON data model, what presentation cannot cross that boundary and what hostile cases should be tested before the output is trusted. It counts values and containers after aliases resolve, not source lines. A successful conversion is evidence about the resolved graph. It is not evidence that comments survived, that anchor identity survived or that an application schema accepts the JSON. “Valid YAML” is intentionally scoped: another YAML implementation can support custom tags or YAML 1.1 implicit values that this tool refuses or reads as strings. ## Inputs ### Typed or pasted YAML Any document accepted by the YAML 1.2 JSON-compatible schema can be the root: mapping, sequence, string, finite number, boolean or null. The input event clears old JSON immediately and starts a 120 millisecond debounce. Conversion then runs in a worker. Each request and response carries a revision. Responses from older requests are ignored after the next request is dispatched; the debounce interval has the timing limitation described below. Paste replaces the source when performed in the field or on the surrounding page. YAML punctuation and whitespace are not cleaned. Clear moves to a neutral empty state and removes output, Copy result, findings tied to the old source and reverse-conversion actions. ### Files The shared drop zone accepts `.yaml`, `.yml`, `application/yaml`, `text/yaml` and plain text. A file over 1,000,000 bytes is refused before parsing. File text stays in the tab. File names are UI hints only and do not affect schema selection. ### Anchors and aliases Acyclic aliases are resolved. JSON has no pointer identity, anchors or aliases, so an aliased mapping appears as an ordinary repeated JSON value. Anchor names never appear in output. At most 100 aliases are accepted by the loader. A cycle such as an object containing an alias to itself is refused because JSON cannot represent a cyclic graph. ### Reverse handoff Take it further sends the valid JSON result to the JSON to YAML page using the one-use same-origin handoff. The document stays out of the URL, but a random one-use transfer token is temporarily placed in its fragment. The payload is stored in session storage and can also be passed through BroadcastChannel, with a 60-second validity window. The destination consumes the transfer and strips the random token from the address. If browser storage and tab communication are unavailable, ordinary navigation still works but does not carry private data. ### Limits ### Timing and handoff boundaries Revision checks begin at dispatch, not at each edit. An earlier worker response can arrive during the 120-millisecond debounce or after Clear and repaint an earlier result. Do not rely on this version for a strict no-stale-output guarantee; wait for the current conversion and compare the output with the source before using it. Reverse handoff temporarily uses session storage and a random URL fragment, with expiry and one-use consumption. ### Format boundaries | Boundary | Limit | Refusal prevents | | --- | ---: | --- | | Source | 1,000,000 characters | Unbounded parsing and worker messages | | YAML aliases | 100 | Alias expansion abuse | | Resolved depth | 80 levels | Hostile nesting | | Resolved tree | 100,000 values and containers | Excessive traversal and output | | Integers | JavaScript safe-integer range | Silent rounding in JSON consumers | | Tags | JSON-compatible schema only | Construction of application-specific objects | ## Reading the result ### Verdict and checks “Converted valid YAML to JSON” means parsing and the bounded tree walk completed. The checks name valid YAML and JSON-model preservation; a chip and validity detail report the resolved node count. A source-text heuristic detects full-line comments and some anchor or alias syntax, adding an Info finding that YAML presentation details were removed. It is not a complete YAML presentation audit: an inline comment can disappear without that note. That note is not a parsing failure; it is a warning against comparing text or expecting a round trip to recreate the original authoring surface. ### Findings Passes establish syntax and JSON-model compatibility. The presentation note names comments, anchors and aliases together because all live above the JSON value model. A failure clears the output and gives a safe explanation, with line and column when the YAML parser supplies them. Parser excerpts are not echoed because source text can contain secrets. ### JSON output The output is pretty-printed with two spaces and a final newline. JavaScript serialization writes negative zero as `0`, so a consumer that distinguishes `-0` needs an explicit representation outside this conversion. Mapping keys become JSON object member names, sequences become arrays, and compatible scalars become their JSON equivalents. The output window wraps long lines so it does not widen the page. Copy result is available only while the current source has a completed result. ### History and next step Break it and Heal it replacements enter History. Revert removes the newest automated change; Reset returns to the first source in the log. Typing starts a new log. The reverse conversion link carries the JSON result into the other page for a semantic round-trip check. ## Method ### Parse with a narrow schema The worker uses the YAML 1.2 JSON-compatible schema. The schema accepts null, booleans, integer and floating-point numbers, strings, sequences and mappings. It does not construct custom tags such as `!include`, JavaScript objects or language-specific values. This is both a security boundary and an interoperability choice: a converter should not execute or instantiate a value merely because a tag names it. The loader also refuses duplicate mapping keys. Choosing the first or last entry would conceal an environment-dependent behavior that QA is supposed to expose. A file that looks reasonable can therefore be rejected when two merged snippets repeat `role`, `image`, `timeout` or another decisive key. ### Scalar and document boundaries The loader accepts one document. Multiple `---` documents are refused rather than combined into an array. Complex mapping keys such as a sequence used as a key are refused. Plain `yes`, a date such as `2026-10-24`, hexadecimal-looking `0x10` and `.inf` remain strings under this schema; they do not become a boolean, date object, hexadecimal integer or infinity. Explicit unsupported tags fail. Test these cases with the consuming loader when migrating from a different schema. ### Resolve then bound the graph After parsing, the tool walks the resolved value iteratively. It keeps an ancestor set to detect cycles, carries depth on the stack and counts primitive values as well as containers. Shared acyclic aliases can be visited in separate branches; an alias to an active ancestor is a cycle and fails. The distinction matters. YAML's [representation graph](https://yaml.org/spec/1.2.2/#chapter-3-processes-and-models) may contain shared nodes, whereas JSON text describes a tree. Repeating an aliased value preserves equality but not object identity. If an application depends on reference identity, JSON is not an equivalent target. ### Check numbers Every number must be finite. Integers must be safely representable because [RFC 8259 section 6](https://www.rfc-editor.org/rfc/rfc8259#section-6) identifies the binary64 exact integer range as the interoperable range. An ID beyond that range is refused instead of rounded. Quote it in YAML only when its application type is a string; update the schema and tests at the same time. ### Serialize JSON The checked value is passed to `JSON.stringify` with two-space indentation. The serializer cannot include comments, directives, tag spelling, anchor names, alias tokens, block-versus-flow choices or quoted-versus-plain scalar style. Key order normally follows enumeration order but is not an application contract. A sequence must carry order when order is semantic. ### Keep the UI truthful during edits Input changes clear the visible output and schedule conversion. The revision advances when conversion is dispatched. The worker returns output, node count and root kind or a safe error, and the page renders only a matching revision. An earlier response can still arrive before the debounce dispatch or after input is cleared, because those actions do not immediately advance the revision. Allow conversion to settle before copying or opening the reverse conversion. ## Standards and conformance ### YAML 1.2.2 | Specification area | Applied here | Where the tool stops | | --- | --- | --- | | [Representation model](https://yaml.org/spec/1.2.2/#chapter-3-processes-and-models) | Parses nodes, mappings, sequences and aliases | Does not preserve presentation events | | [JSON schema](https://yaml.org/spec/1.2.2/#102-json-schema) | Resolves JSON-compatible scalar types | Does not use YAML 1.1 implicit typing | | [Node anchors](https://yaml.org/spec/1.2.2/#3222-anchors-and-aliases) | Resolves bounded acyclic aliases | Does not preserve anchor names or identity | | [Tags](https://yaml.org/spec/1.2.2/#3212-tags) | Accepts tags known to the JSON schema | Refuses application and language-specific tags | The specification says anchors identify nodes in a serialization, while alias events refer to the most recent node with that anchor. JSON offers no equivalent syntax. Flattening an acyclic alias is therefore disclosed rather than described as lossless presentation. ### RFC 8259 The output follows the JSON value grammar in [section 3](https://www.rfc-editor.org/rfc/rfc8259#section-3), object model in [section 4](https://www.rfc-editor.org/rfc/rfc8259#section-4), array order in [section 5](https://www.rfc-editor.org/rfc/rfc8259#section-5) and numeric interoperability boundary in [section 6](https://www.rfc-editor.org/rfc/rfc8259#section-6). The tool does not claim canonical JSON and does not normalize Unicode. ## Finding reference ### Failures | Finding | Meaning | QA consequence | Fix | | --- | --- | --- | --- | | Invalid YAML | Syntax, duplicate key or unsupported tag was found | Different loaders could disagree or refuse it | Correct the named line and column | | Unsafe integer | JSON consumers can round the value | IDs can point to the wrong record | Quote intentionally and require a string | | Circular YAML aliases | The resolved graph is cyclic | JSON cannot encode the structure | Replace the cycle with an explicit identifier | | Too many aliases | Expansion budget was exceeded | Small source may create excessive work | Remove reuse or split the file | | Document too complex | Depth or resolved node budget was exceeded | Conversion can consume excessive resources | Flatten or split the document | ### Successful and informational findings | Finding | Status | Proves | Does not prove | | --- | --- | --- | --- | | Valid YAML | Pass | The narrow parser accepted the whole source | Every YAML loader accepts it | | JSON data model preserved | Pass | Checked values were serialized as JSON | Presentation or every numeric distinction survives | | Presentation details removed | Info | Comments or alias syntax were detected | Their intent was unimportant | ## Guide ### Audit a legitimate-looking fixture 1. Paste the YAML and wait for the completed verdict. 2. Read presentation notes before copying. A comment may contain an operator instruction that JSON cannot carry. 3. Choose Break it → Duplicate key. Verify the page refuses the file rather than silently choosing the apparent safe or dangerous value. 4. Choose Break it → Unsafe integer. Check whether the field is a quantity or an identifier. Identifiers often belong in strings. 5. Test a self-alias: the expected outcome is a cycle refusal, not a frozen tab. 6. Open the reverse converter and compare parsed values after converting back. 7. Validate the JSON with the consuming application's schema and run its tests. ### Check independently Use the exact YAML library and schema the application deploys. A Node.js project with a locked `js-yaml` dependency can compare resolved values: ```js import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { load, JSON_SCHEMA } from 'js-yaml'; const yaml = load(readFileSync('fixture.yaml', 'utf8'), { schema: JSON_SCHEMA }); const json = JSON.parse(readFileSync('fixture.json', 'utf8')); assert.deepEqual(json, yaml); ``` This confirms the chosen parser's value model. It does not test comments or anchor identity because the JSON target cannot hold them. Run the comparison in CI beside the application's schema validation. ### Break it and manual edge cases | Case | Source | Expected behavior | | --- | --- | --- | | Duplicate key | `role` appears twice | Refused without selecting either value | | Unsafe integer | `9007199254740993` | Refused before JSON serialization | | Malformed flow value | Unclosed `[` | Refused and stale JSON cleared | | Circular alias | A node aliases itself | Refused during the bounded graph walk | | Comment and alias | Valid acyclic YAML | Converted with a presentation note | ### Preserve intent that JSON cannot carry Move operational comments into documentation or a companion README. Replace anchors used only for convenience with repeated values or generate the files from a typed source. Replace genuine graph identity with explicit IDs and references, then teach the consumer to resolve them. Replace custom tags with ordinary tagged objects only when the application contract defines that shape, for example `{ "kind": "include", "path": "fixture.json" }`; the converter will not invent such a mapping. ## Worked example The opening YAML maps `suite` to `checkout`, `cases` to a two-item sequence and `enabled` to a boolean. Each case mapping holds a name and expected status. The JSON output keeps the sequence order and scalar kinds. It does not include YAML indentation because indentation is presentation, not a value. Add a comment above `enabled`. The JSON remains semantically equal and the page adds a presentation note. Add an anchor to the first case and alias it as another field. The value resolves and is repeated in JSON, while the note explains that alias identity disappeared. Make the alias point to an ancestor and conversion stops. This progression distinguishes safe presentation loss from a structure JSON cannot represent. For a completed invalid conversion, the output is cleared. Rapid edits during an outstanding worker request need the additional timing caution below. ## For agents Remote automation may call `yaml_to_json` with an `application/yaml` text artifact and indentation from 0 through 8. Remote use transmits the source to Tamperbox infrastructure, unlike the browser page. An agent must retain provenance and limitations, report presentation loss, and never describe a resolved alias as proof that object identity was preserved. When diagnosing a production/configuration issue, ask which YAML library, YAML version and schema the consumer uses. Run duplicate-key, numeric-boundary, tag and alias tests with that implementation. Do not “fix” a rejected duplicate by selecting the value that seems legitimate; that is exactly the ambiguity an adversarial QA case should surface. ## Limits ### Timing and handoff boundaries Revision checks begin at dispatch, not at each edit. An earlier worker response can arrive during the 120-millisecond debounce or after Clear and repaint an earlier result. Do not rely on this version for a strict no-stale-output guarantee; wait for the current conversion and compare the output with the source before using it. Reverse handoff temporarily uses session storage and a random URL fragment, with expiry and one-use consumption. ### Format boundaries The tool is not a general YAML editor, linter or canonicalizer. It does not preserve comments, directives, custom tags, anchor names, alias identity, flow style, block scalar chomping, quotes or numeric spelling. It does not validate Kubernetes, CI, Compose or another product schema. Its line and column are parser diagnostics, not a guarantee that every loader reports the same position. Browser-local processing ends if the user chooses the remote API or MCP operation. ## References - [YAML 1.2.2](https://yaml.org/spec/1.2.2/), including [processes and models](https://yaml.org/spec/1.2.2/#chapter-3-processes-and-models), [anchors and aliases](https://yaml.org/spec/1.2.2/#3222-anchors-and-aliases), [tags](https://yaml.org/spec/1.2.2/#3212-tags) and the [JSON schema](https://yaml.org/spec/1.2.2/#102-json-schema). - [RFC 8259](https://www.rfc-editor.org/rfc/rfc8259), especially [values](https://www.rfc-editor.org/rfc/rfc8259#section-3), [objects](https://www.rfc-editor.org/rfc/rfc8259#section-4), [arrays](https://www.rfc-editor.org/rfc/rfc8259#section-5) and [numbers](https://www.rfc-editor.org/rfc/rfc8259#section-6). Internet Standard.