Skip to content

Ironfang Security

Ironfang Security docs

How the External Security Check works, from adding a domain to rechecking a fix, and the API behind the portal.

How it works

Everything happens in the portal under Security, in this order:

  1. Add a domain. Paste a domain or URL. IP addresses, public suffixes and reserved names are refused.
  2. Verify it. Add the TXT record the portal shows. It is checked automatically, or on demand.
  3. Confirm authorisation. Review the scan policy and confirm you are authorised to test the domain.
  4. Run a scan. The verification record is checked again, then every category runs.
  5. Review findings. Findings are ranked by severity and confidence, each with evidence and a fix.
  6. Recheck. The checks behind a finding run again. If the issue is gone, the finding is marked fixed.

Start in the portal. The sections below cover each step in detail.

Verifying a domain

Verification uses a DNS TXT record at _ironfang-verification.<domain> containing ironfang-verification=<token>, with the token from the portal. Only someone who controls the domain's DNS can publish it.

The record, for example.com

Type
TXT
Name
_ironfang-verification.example.com
Value
ironfang-verification=k3v9q2mz7x4t8w1r

Most providers add the domain for you

At most DNS providers the host or name field appends your domain automatically, so enter only _ironfang-verification. Entering the full name creates _ironfang-verification.example.com.example.com, which is never found. The portal shows both the full name and the host label for this reason.

At your DNS provider

ProviderWhere and what to enter
CloudflareDNS, then Records, then Add record. Type TXT, Name the host label, Content the value. TTL Auto is fine. TXT records are never proxied.
Amazon Route 53Hosted zones, the domain's zone, then Create record. Record name is the host label (the zone name is shown after it), type TXT, and the value in double quotes.
GoDaddyDomain Portfolio, the domain, then DNS and Add New Record. Type TXT, Name the host label, Value the value.
NamecheapDomain List, Manage, then Advanced DNS and Add New Record. Choose TXT Record, Host the host label, Value the value.
Azure DNSThe DNS zone, then Record sets and Add. Name the host label, type TXT, Value the value.
Google Cloud DNSCloud DNS, the zone, then Add standard. DNS name the host label (the zone is shown after it), resource record type TXT, and the value as TXT data.
Other providersLook for TXT records in the DNS settings. If the host field shows your domain after it, enter only the host label; if it is blank with no suffix, enter the full name.

Checking the record yourself

Query a public resolver with dig +short TXT _ironfang-verification.example.com @1.1.1.1 or, on Windows, nslookup -type=TXT _ironfang-verification.example.com 1.1.1.1. The answer should contain the value exactly, with nothing before or after it.

$ dig +short TXT _ironfang-verification.example.com @1.1.1.1
"ironfang-verification=k3v9q2mz7x4t8w1r"

Statuses

ValueMeaning
waitingThe record has not been seen yet. Ironfang keeps checking automatically.
checkingA lookup is in progress.
verifiedThe record was found with the correct value. Scans can be authorised and run.
failedVerification did not succeed. The portal shows why and lists the TXT values it found. Fix the record and check again, or issue a new token.
expiredThe record was not found before the token expired. Issue a new token and update the record.
lapsedThe domain was verified, but the record was missing when it was checked before a scan. Add it back to verify again.

A token is valid for 7 days and can be replaced at any time before the domain is verified. You can request an immediate check once every 10 seconds per domain. Keep the record in place: it is checked again before every scan.

Troubleshooting

  • Check the name first. A doubled domain from the host field is the most common cause.
  • Wait a few minutes after adding the record. If a lookup ran before the record existed, resolvers may cache the empty answer for a while.
  • Copy the value exactly. Quotes added by your provider are fine; extra spaces or a missing part of the token are not.
  • Several TXT values at the same name are fine. A CNAME at that name is not: TXT and CNAME cannot share a name.

Authorisation and scan policy

Verification proves control, not consent. Before the first scan of a domain, someone in your organisation confirms: I confirm I am authorised to assess this domain.

The confirmation is recorded with the person, the time and the scan policy version (currently external-check-v1), and cannot be edited. When the policy changes, scans pause until someone confirms the new version.

Included

  • DNS: address and nameserver records, CAA, DNSSEC and dangling records.
  • TLS and HTTPS: the certificate, supported TLS versions and cipher strength.
  • HTTP security: redirects, security headers, cookies and security.txt, from a handful of ordinary requests.
  • Email authentication: SPF, DMARC, DKIM and MX records. No email is sent.
  • Exposed services: one connection attempt per port on a fixed list of common services. Nothing is sent to them.
  • Technology: the web server, CDN and frameworks your responses disclose.
  • Outdated software: versions that look unsupported, reported as potential issues.
  • Certificate transparency: hostnames from public logs, listed for review and never scanned.

Never attempted

Exploitation, password and credential attacks, authentication attacks, SQL injection, cross-site scripting, fuzzing, denial-of-service and destructive testing, social engineering and attempts to gain access.

Every scan and result includes this statement: This is an automated external security check. It is not a penetration test, a certification or a formal assessment.

Running a check

A full scan runs every category: DNS, email, TLS, HTTP, technology, exposed services and certificate transparency. Most finish within a few minutes, and the portal shows progress by category.

Scan statuses

ValueMeaning
queuedAccepted and waiting for a scanner.
runningChecks are in progress.
completedEvery check ran.
partialFinished, but some checks could not complete. They are listed as errors, so a missing result is never shown as a pass.
failedThe scan could not run. The reason is given.
cancelledStopped by someone in your organisation.
killedStopped by Ironfang, for example while scanning is paused for maintenance. The reason is given.

A finished scan lists findings, passed checks, observations such as detected technologies, checks that could not complete, known limitations and recommended next actions. Scan history records what was new, fixed or reopened each time.

Hostnames found in certificate transparency logs appear as discoveries on the domain. They are listed for review and never scanned automatically.

Severity and confidence

Every finding has a severity and a separate confidence. Severity is the potential impact; confidence is how strongly the evidence supports the finding. There is no combined score.

Severity

ValueMeaning
criticalSerious exposure. Fix immediately.
highSignificant weakness. Fix soon.
mediumWorth fixing.
lowMinor hardening.
infoContext, not a problem.

Confidence

ValueMeaning
confirmedObserved directly.
highStrong evidence.
mediumLikely. Worth verifying.
lowInferred, for example from a version string. Shown as "Potential". Verify before acting.

Kind

ValueMeaning
issueA security issue.
hardeningRecommended hardening: a protection that is missing or weak.
informationalContext, not a problem.
potential_vulnerabilityA possible vulnerability inferred from what the server advertises.

Finding statuses

ValueMeaning
openNeeds attention.
acknowledgedSeen and being worked on.
fixedA scan or recheck confirmed the issue is gone. Only Ironfang sets this status.
accepted_riskLeft as is, deliberately.
false_positiveNot an issue in your setup.
needs_reviewCould not be decided automatically. Needs review by a person.

You can set open, acknowledged, accepted risk or false positive, with a note. Every change is kept in the finding's history.

Each finding keeps the evidence behind it: a DNS answer, certificate, TLS handshake, HTTP response, TCP connection, service greeting or certificate transparency entry.

Every finding links to its page in the check reference: what the check looks at, why it matters and how to fix it.

Rechecking a fix

After a fix, recheck the finding instead of running a full scan. The checks behind it run again on its host:

  • If the issue is gone, the finding is marked fixed.
  • If it is still there, the finding stays open.
  • Either way, the new evidence and result are added to its history.

A finding can be rechecked once every 60 seconds. Full scans also mark findings fixed, or reopen them if the issue returns.

Limits

Free during the preview, with the same limits for every organisation. Requests over a limit return an error code and, for cooldowns, when to retry.

  • 5 domains per organisation, of which at most 5 may be waiting for verification.
  • One full scan of a domain every 60 minutes.
  • 20 scans a day per organisation.
  • 1 scan running at a time per organisation.
  • One recheck of a finding every 60 seconds.

Each scan makes at most 8 HTTP requests per host and 2 concurrent connections per address, with 150 milliseconds between connection attempts.

The scanner page lists its source addresses and User-Agent for allowlisting.

Authentication

The Security API is the API the portal uses. During the preview it accepts a Warden user token as a bearer token, with the organisation named in X-Ironfang-Tenant.

Authorization: Bearer <Warden user token>
X-Ironfang-Tenant: <organisation id>

Each request also needs a permission in that organisation, checked on every call:

  • security.readReading: the overview, domains, scans, findings, activity and the scan policy.
  • security.writeChanging anything: adding and removing domains, verification checks, authorisation, starting and cancelling scans, finding statuses and rechecks.

Platform API keys and delegated MCP tokens are refused with 403 api_keys_not_supported during the preview. A missing permission is 403; a failed permission lookup is 503.

API

Base URL https://api.ironfang.com/security. The contract is OpenAPI 3.1 at https://api.ironfang.com/security/openapi.yaml, also as JSON at the same path with .json. Every object belongs to one organisation: anything in another is reported as not found.

EndpointPermissionWhat it does
GET /v1/statussecurity.readWhether Security is enabled, paused or switched off, the limits, and the scanner identity.
GET /v1/overviewsecurity.readDomains, open findings by severity, the latest scan, recommended actions and recent activity.
GET /v1/scan-policysecurity.readThe current scan policy and the statement to confirm.
GET /v1/domainssecurity.readThe organisation's domains.
POST /v1/domainssecurity.writeAdd a domain and issue its verification challenge.
GET /v1/domains/{domainId}security.readOne domain, with its verification and authorisation.
DELETE /v1/domains/{domainId}security.writeStop all checks of a domain. Its history is kept.
POST /v1/domains/{domainId}/verification/checksecurity.writeLook up the verification record now.
POST /v1/domains/{domainId}/verification/renewsecurity.writeReplace an expired or failed token.
POST /v1/domains/{domainId}/authorisationsecurity.writeConfirm authorisation under the current policy.
POST /v1/domains/{domainId}/scanssecurity.writeRun the External Security Check.
GET /v1/domains/{domainId}/discoveriessecurity.readNames found in certificate transparency logs.
GET /v1/scanssecurity.readScan history, newest first.
GET /v1/scans/{scanId}security.readA scan and its results.
POST /v1/scans/{scanId}/cancelsecurity.writeCancel a queued or running scan.
GET /v1/findingssecurity.readFindings, most severe first.
GET /v1/findings/{findingId}security.readA finding with its evidence, guidance and history.
PATCH /v1/findings/{findingId}security.writeChange a finding's status, with a note.
POST /v1/findings/{findingId}/rechecksecurity.writeRecheck a finding.
GET /v1/activitysecurity.readWhat happened in the organisation's Security account.

Errors

Every error is the same JSON shape. Branch on the code and the HTTP status, never on the message. Cooldowns and rate limits add retry_after_seconds and a Retry-After header.

{
  "error": {
    "code": "scan_cooldown",
    "message": "This domain was scanned recently.",
    "docs": "https://ironfang.com/security/docs#errors",
    "retry_after_seconds": 1740
  },
  "request_id": "01a0c375-7bae-7f02-a3d4-91e6b8c25f70"
}
CodeMeaning
unauthorizedNo valid token.
forbiddenThe token lacks the permission in this organisation.
api_keys_not_supportedA platform API key or MCP token was sent. Use the portal during the preview.
invalid_tenantX-Ironfang-Tenant does not name an organisation the token can act in.
permissions_unavailableYour permissions could not be looked up just now. Try again.
not_foundNo such object in this organisation.
invalid_bodyThe request body could not be read as JSON.
body_too_largeThe request body is larger than the API accepts.
validation_failedThe request body is not valid.
domain_invalidNot a domain that can be checked: an IP address, a public suffix or a reserved name.
domain_existsThe domain is already in the organisation.
domain_limit_reachedThe organisation has reached its domain limit.
verification_pending_limitToo many domains are waiting for verification.
verification_requiredThe domain is not verified, or its record has gone.
already_verifiedThe domain is already verified, so its token cannot be replaced.
verification_expiredThe verification token has expired. Issue a new one.
verification_unavailableThe verification record could not be looked up just now. Try again shortly.
authorisation_requiredAuthorisation has not been confirmed for this domain.
policy_outdatedThe scan policy has changed; confirm the new version.
scan_in_progressThe organisation already has a scan running.
scan_cooldownThe domain was scanned too recently.
daily_limit_reachedThe organisation has used its scans for today.
domain_rate_limitedThe domain has been checked several times in the last hour, across organisations. Try again later.
scan_not_activeThe scan has already finished, so it cannot be cancelled.
recheck_unavailableThis finding cannot be rechecked now.
recheck_cooldownThe finding was rechecked too recently.
finding_fixedThe finding is already fixed.
check_rate_limitedVerification lookups for this domain are too frequent.
organisation_suspendedSecurity is suspended for this organisation. Contact us.
scans_pausedScanning is paused. Results can still be read.
security_disabledIronfang Security is temporarily unavailable.
security_unavailableThe Security service could not be reached. Try again.
security_timeoutThe Security service took too long to answer. Try again.
internalSomething went wrong on our side. The request id helps us find it.

What it is not

Machine interfaces

InterfaceDetails
Product pagehttps://ironfang.com/security
Documentationhttps://ironfang.com/security/docs
API base URLhttps://api.ironfang.com/security
OpenAPI contracthttps://api.ironfang.com/security/openapi.yaml. The same contract is served as JSON at https://api.ironfang.com/security/openapi.json.
AuthenticationA signed-in user's Warden token; platform API keys are not accepted yet
Errorshttps://ironfang.com/security/docs#errors. A JSON body with a stable code, a message, this link and the request id.
MCPNot available. Not yet available over MCP. Domains, verification, scans, findings and rechecks are in the portal; during the preview the Security API takes a signed-in user's token and refuses delegated MCP tokens and API keys. MCP server reference; every tool and schema without a token at /.well-known/ironfang-mcp.json
Discovery/apis.json, /.well-known/api-catalog and /llms.txt