ismycodesafe.com

Scanner Methodology

What the scanner sends to your site, how each result is produced, how findings are mapped to the OWASP Top 10, and exactly how the A to F grade is calculated. Written from the scanner source, so you can check a claim on the site against what the code does. For the output itself, see the sample report.

How a scan runs

A scan takes one URL and runs in waves, each wave in parallel with its own timeout. A full scan finishes in 30 to 60 seconds. The target is validated first: addresses in private, loopback and cloud-metadata ranges are refused, DNS is resolved once and the probes connect to that validated address, and every redirect hop is re-validated before it is fetched. A check that fails or times out returns an empty result and never aborts the scan.

The scanner produces 31 result families, listed below, plus four derived values: the CVE list, the OWASP mapping, the grade and its colour. The TypeScript result type documents 28 of the 31; ai_readiness, protocol_extras and a thirty-first internal key (site_owner, used only to choose the language of follow-up e-mail and not a security check) were added later.

There is deliberately no single "number of checks" on this page. A check has no fixed unit: one family can be one handshake or seventy-one path probes. The counts you see below are the lengths of the lists in the code.

What the scanner sends, and what it does not

Most of it is what a browser or search bot would send: a GET for the homepage, GETs for 71 well-known paths, a TLS handshake, DNS queries. Response bodies are read only for the homepage and error pages (capped at 2 MB); path probes read the status line and headers and stop.

Some probes go beyond reading. These are all of them:

Nothing is exploited. No payload is sent that tries to read, change or delete data, no credentials are submitted or guessed, and no brute force is attempted. The PUT and DELETE requests carry no body, but a server that treats a bodiless PUT or DELETE on its root URL as a real operation would act on it. That is a rare configuration, and it is the reason to scan only sites you own or have permission to scan.

Some lookups go to third parties, who then see the scanned URL or domain: VirusTotal (when configured), PhishTank, AlienVault OTX, URLhaus, Spamhaus, urlscan.io (unlisted, when configured), crt.sh and Shodan InternetDB, plus NVD, OSV and the retire.js database on GitHub for version matching.

The 31 result families

For each family: how it is probed, and what it contributes to the grade. "Not graded" means the result appears in the report but changes neither the OWASP mapping nor the letter.

Transport and TLS

FamilyHow it is probedContribution to grade
sslOne TLS handshake to port 443 on the validated IP with certificate verification on. Reads issuer, expiry and the negotiated protocol.A02 when the handshake fails verification.
ssl_deepSSLyze against port 443: certificate chain, SSL 2.0, SSL 3.0 and TLS 1.0 to 1.3 cipher suites, Heartbleed, TLS compression, and a hostname match against the leaf certificate.A02, but only for critical or high issues: SSL 2.0/3.0, TLS 1.0/1.1, Heartbleed, compression, hostname mismatch. A missing TLS 1.3 is reported and not graded.
redirectsA GET to the http:// form of the URL with automatic redirects off. The Location chain is followed by hand, up to 10 hops, re-validating each host.A02 for every redirect finding, including low-risk ones such as a 302 or a chain longer than 3 hops.
headersOne request, headers only, for 7 security headers: Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, Cross-Origin-Opener-Policy. Server, X-Powered-By and X-AspNet(Mvc)-Version are flagged only when the value contains a digit.A02 when HSTS is absent. A05 when 3 or more of the 7 are missing, and for each versioned server header.
cookiesReads Set-Cookie on the homepage response and flags a missing Secure, HttpOnly or SameSite attribute per cookie.Not graded. Shown in the report only.

Web application surface

FamilyHow it is probedContribution to grade
corsTwo requests, one with Origin: https://evil.com and one with Origin: null. Flags an echoed origin, and a wildcard origin combined with credentials.A01.
methodsSends TRACE, DELETE and PUT to the URL with redirects off. A method is flagged when the status is not 403, 404, 405 or 501.A01.
owasp71 GET requests for well-known paths (.env, .git, backup archives, SQL dumps, phpMyAdmin, debug and CI files, security.txt and others). Status only; a body is never downloaded. Redirects are not followed. A 200 counts as a hit.A01 for paths containing admin, panel or manager. A03 for .env, .git, phpinfo, .htaccess, web.config. A09 when security.txt is absent.
contentReads the homepage HTML (capped at 2 MB). Looks for http:// resources on an https page, external scripts and stylesheets without an integrity attribute, forms that post over http, forms without a CSRF-style field, stack-trace and debug strings, and sensitive words in HTML comments.A08 for mixed content and missing SRI. Forms and information disclosure are not graded.
authGETs 18 common login and admin paths and parses any form found: CSRF field, autocomplete on the password field, CAPTCHA provider, rate-limit headers, MFA wording, password minlength and maxlength. No credential is ever submitted.A07, and A02 when a login form is served over http.
rate_limitingFive sequential GET requests to the URL. Looks for a 429 or an X-RateLimit-* header.A07 only when neither is seen and no login page was found. Five requests will rarely trigger a limit, so this is a weak signal.
error_pagesRequests /this-path-does-not-exist-8f4a2b7c and /index.php?id=1' and matches the bodies against keyword lists for stack traces, framework names, file paths, debug text and runtime versions.A05.
wafChecks response headers and the Server header against known WAF signatures. If none match, sends one request carrying ?id=1' OR 1=1-- and treats a 403 or 406 as an unnamed WAF.Not graded.

Network and DNS

FamilyHow it is probedContribution to grade
portsA TCP connect (3 second timeout, no banner read) to 10 ports: 21, 22, 23, 25, 3306, 5432, 6379, 8080, 8443, 27017.A03, Critical, only for 3306, 5432, 6379 and 27017. The other six are reported, not graded.
dnsDNS queries for MX, NS, CAA, SPF, DMARC, MTA-STS, TLS-RPT and 10 DKIM selectors (default, google, selector1, selector2, k1, k2, dkim, mail, s1, s2).A09 for a missing CAA record only. SPF, DMARC, DKIM, MTA-STS and TLS-RPT are shown and not graded. A custom DKIM selector will be reported as absent.
ftpConnects to port 21 and attempts an anonymous login.Not graded.
smtpConnects on 587, 465 and 25 and checks for STARTTLS or implicit TLS. It does not test for open relaying and sends no mail.Not graded.
subdomainsQueries crt.sh for certificates issued under the domain and flags names containing staging, dev, test, admin, internal, vpn or api.Not graded. The separate cert_transparency family below is.
blacklistResolves the IPv4 address and queries 5 DNS blocklist zones.Not graded.

Technology and known vulnerabilities

FamilyHow it is probedContribution to grade
tech_stackMatches the Server and X-Powered-By headers, the HTML generator tag, framework markers in the page and cookie names against built-in pattern lists (8 server, 5 powered-by, 11 HTML, 7 cookie patterns).Indirectly. Each detected name and version (first 10) is looked up in NVD, and matches appear under A06.
js_librariesFinds versioned script URLs (CDN paths such as lib@1.2.3, lib-1.2.3.min.js) and normalises 18 well-known library names.Indirectly. The first 20 libraries are looked up in OSV, and matches appear under A06.
js_vulnerabilitiesCompares detected library versions with the retire.js vulnerability database, fetched from GitHub on each scan.A06, for critical and high matches only (first 5 reported).
shodanLooks up the resolved IP in Shodan InternetDB. This is Shodan's existing data; the scanner sends nothing to your server for it.A06 for CVEs listed against the IP. A05 for 12 risky ports (21, 23, 25, 445, 1433, 1521, 3306, 3389, 5432, 5900, 6379, 27017).

Reputation and third-party sources

FamilyHow it is probedContribution to grade
threat_intelAsks five sources about the URL or domain: VirusTotal, PhishTank, AlienVault OTX, abuse.ch URLhaus and Spamhaus DBL. VirusTotal needs an API key and reports itself unavailable without one.VirusTotal, URLhaus and Spamhaus: A05. PhishTank: A01. OTX pulse count above zero: A09. An unavailable source contributes nothing.
cert_transparencyQueries crt.sh and flags subdomain names containing admin, staging, dev, test, internal, vpn, api, debug, backup, old or legacy.A05.
urlscanSubmits the URL to urlscan.io as an unlisted scan and reads the verdict. Needs an API key and reports itself unavailable without one.A05 when flagged malicious.

SEO and AI search (separate grades, never part of the security grade)

FamilyHow it is probedContribution to grade
seo21 on-page checks, reported with their own grade.Not part of the security grade.
ai_content17 checks for patterns typical of AI-generated copy, with their own grade.Not part of the security grade.
ai_readiness10 checks of how readable the page is to AI search engines, with their own grade.Not part of the security grade.
protocol_extrasLightweight protocol, compression, caching and discoverability checks that share one HEAD and one GET request.Not part of the security grade.

OWASP Top 10 mapping

Findings are filed under OWASP Top 10 (2021) categories by rules in the analyser, not by a language model. Each category with at least one finding gets one risk level from the rule in the right-hand column. A04 Insecure Design and A10 Server-Side Request Forgery are never produced.

CategoryWhat files a finding hereRisk level
A01 Broken Access ControlCORS findings, dangerous HTTP methods, paths containing admin/panel/manager that answer 200, a PhishTank hit.High if any finding mentions admin, otherwise Medium
A02 Cryptographic FailuresFailed certificate verification, missing HSTS, any redirect finding, login form over http, critical or high SSLyze issues.High if a finding mentions ssl or certificate, otherwise Medium
A03 InjectionExposed .env, .git, phpinfo, .htaccess, web.config; open database ports.Critical for a database port or .env, otherwise High
A05 Security Misconfiguration3 or more missing headers, versioned server headers, leaking error pages, risky Shodan ports, risky subdomain names, VirusTotal, URLhaus, Spamhaus or urlscan flags.Medium
A06 Vulnerable and Outdated ComponentsCVEs from NVD and OSV, Shodan CVEs, critical or high retire.js matches.Critical if any CVE is critical, High if any is high, otherwise Medium
A07 Identification and Authentication FailuresLogin-page findings (CSRF, autocomplete, CAPTCHA, MFA wording, password length rules, default admin panels), and the generic no-rate-limiting finding.High if a finding mentions CSRF, otherwise Medium
A08 Software and Data Integrity FailuresExternal scripts and stylesheets without SRI, mixed content.Medium
A09 Security Logging and Monitoring FailuresNo CAA record, no security.txt, an AlienVault OTX pulse count above zero.Low

How the A to F grade is calculated

The grade is computed from the risk level of each OWASP category, not from individual findings. The analyser counts how many categories are Critical, High and Medium (Low is ignored). The code tests the rules from F down to A and the first match wins, so a result that satisfies both E and F is an F:

GradeRule
ANo Critical category, no High category, at most 1 Medium category.
BNo Critical, no High, 2 or more Medium categories.
CNo Critical, 1 or 2 High categories.
D1 Critical category, or 3 or more High categories, with no more than 1 Critical.
E2 Critical categories (and fewer than 2 High).
F3 or more Critical categories, or 2 Critical and 2 or more High.

In the current rules only A03 and A06 can ever be Critical, so at most two categories reach Critical. That means 3 Critical categories is out of reach and F requires the second branch: A03 and A06 both Critical plus at least two High categories.

The grade is a rough ranking of how many separate areas have problems. It is not a risk assessment, and it is not comparable with the grade of another tool.

Limitations and false positives

Each of these follows from how the code works today. They are the reasons to read a finding as a lead to verify, not as a verdict.

See it applied

The sample report shows real output with the evidence behind each finding. The scanner is built and run by Roy Morken. If a statement on this page does not match what you see in a scan, that is a bug in one of them, and I want to hear about it.

Scan your site

This page covers the scanner itself. For how the SSL Labs comparison was measured, which domains it used and what it deliberately left out, see the benchmark methodology. The two are separate documents and neither supersedes the other.