A complete h0SINT case study on our own domain: what it found, what it got wrong, what we changed, and what the next scan measured.
The real h0SINT interface, loaded with this scan. Click through every tab, open any finding, follow its evidence chain back to the request that produced it. Read-only — every control that would start a scan, run a tool or call a model has been removed, not just disabled.
The live demo above is the application, so the screenshots that used to sit here were redundant. What it could not show you is what leaves the building. These are the actual files h0SINT produced from the h0sint.com scan — not mock-ups, not a template with the numbers swapped. Pick a format to see inside it before you download.
try.h0sint.com and tease.h0sint.com: a
public container running our own application on the open internet to serve a self-service scan.
Reviewing our exposure the way we review a client's, the honest conclusion was that the endpoint
was worth less than the attack surface it created — ten unauthenticated write endpoints, file
uploads, and passive scan records accumulating on third-party domains. Both hosts are gone;
dig try.h0sint.com returns NXDOMAIN. The interactive scan now runs as a stateless
function that stores nothing, and the application is private. The findings are left on this page
exactly as they were measured. Removing the host is the fix, and deleting the history
would defeat the point of publishing it.
Every row was found by the tool, fixed by us, and re-verified externally. You can check all of them yourself from a terminal, right now — they are live DNS and HTTP facts, not screenshots.
| Finding | Before | After | Verify it yourself |
|---|---|---|---|
| README.md published, leaking our CDN account id and internal architecture The path still answers 200 — it now serves a placeholder naming our security contact and nothing else. The leaking file is gone; the path is not. |
exposed | leak removed ✓ | curl h0sint.com/README.md |
| Soft-404 — every unknown path returned HTTP 200 | 200 | 404 ✓ | curl -I h0sint.com/anything |
| Security headers absent | 0 families | 7 families ✓ | curl -I h0sint.com |
| No DMARC — anyone could spoof our email | absent | published ✓ | dig TXT _dmarc.h0sint.com |
| No DKIM | absent | 2048-bit key ✓ | dig TXT google._domainkey.h0sint.com |
| No CAA — any CA could issue for us | 0 records | 13 records ✓ | dig CAA h0sint.com |
| No DNSSEC | disabled | signed & validating ✓ | delv h0sint.com |
| Open service on the origin — a control API reachable from the internet | exposed | firewalled + disabled ✓ | — |
Three false positives, all still visible in the data, none of them deleted.
The first scan reported two MEDIUM findings: an exposed Dockerfile and exposed
.github/workflows. Both were false.
/Dockerfile → HTTP 200 /.github/workflows/ci.yml → HTTP 200 /totally-made-up-path-xyz123 → HTTP 200 ← control, byte-identical
Our marketing site answered 200 for every unknown path, so the scanner saw 200 and inferred
the files existed. A control path proved it. We fixed the root cause rather than suppressing the
findings forever: the site now returns real 404s, so the condition that produced them is gone —
curl -I h0sint.com/Dockerfile returns 404 today.
And a point of precision we insist on: the tool still does not claim these are resolved. It carries them as unconfirmed, last seen 2026-07-12, because the nuclei templates that raised them have not re-run against the fixed site. Unconfirmed is not fixed. A scanner that quietly downgrades findings it never re-checked is flattering you, not informing you — and it would be trivially easy for us to let it, on our own case-study page.
A later scan raised a finding from hunt: a “potentially interesting parameter.
Name: [profile] Parameter Type: [HEADER] Categories: [Insecure Direct Object Reference]” against
try.h0sint.com. IDOR on a public funnel would be serious, so we checked it rather
than filing it.
grep for a 'profile' header in the app → no match response headers on try.h0sint.com/ → no such header 'profile' in the served HTML → 0 occurrences
There was no profile header anywhere in the application or its output.
hunt flags parameter names heuristically by category, and this one matched a word
rather than a real input. False positive — worth showing, because a tool that only publishes its
hits is advertising, not evidence.
The finding that mattered was newsletters flagging our waitlist and free-scan
forms as “a Newsletter Submission Form that could be used for email bombing attacks”. That one
landed. Those forms sent a real acknowledgement email, so an attacker submitting someone else's
address repeatedly would make us the one mailing a stranger. A per-IP throttle was the
only defence, and that is exactly what a distributed submitter walks around.
The contact form turned out to be the worse of the two, which we only saw while fixing the first: its acknowledgement quoted the submitted message back to the submitted address. Both are chosen by whoever posts the form, so it was a relay — arbitrary text delivered to a victim of the sender's choosing, from our own DKIM-signed domain.
The waitlist now uses confirmed opt-in: a submission stores the address as pending with a single-use token and sends only a “did you sign up?” message, so nothing reaches the list, our inbox or our CRM until the recipient clicks. We first did the same to the contact form and then undid it — it closed the hole, but nobody makes you confirm an email before your message reaches a company, and it delayed a real enquiry by a day. The contact form now mails the submitter nothing at all; it just notifies us. That removes the relay outright rather than gating it, and costs the sender nothing, because what they wanted was a human reply. Spam is handled locally by a honeypot field and a minimum fill time, so the visitor is never asked to prove anything.
Not a screenshot of a dashboard — the real content the report renders, from the same data model every export format reads. Numbers below are from the scan of 2026-08-06: a full bbot run, 16m29s, 1,349 events, followed by all 19 arsenal tools and all 40 OSINT modules.
The raw scan produced 387 finding events. The report publishes none of them as active, and says exactly why for each bucket:
| Bucket | Count | What it means |
|---|---|---|
| Active | 0 | Nothing was confirmed by this scan. Not "we found nothing" — nothing survived triage and re-testing. |
| Resolved | 1 | The email-bombing finding on tease.h0sint.com, last seen 2026-07-30. The
module that raised it re-ran and did not re-find it. That is the only basis on which this
tool will say "resolved". |
| Suppressed | 30 | Triaged as noise or false-positive, with the evidence retained. They are not deleted and can be re-opened. |
| Unconfirmed | 6 | The nuclei Dockerfile / workflow disclosures from §2. Carried, not counted, not claimed fixed. |
| Signal | Observed |
|---|---|
| Edge / WAF | Cloudflare across the root domain and its subdomains (AS13335) |
| Owned IPs | 0 — all 132 observed addresses are CDN/cloud-fronted, so none is an asset we operate. A bare "0" would read as a broken report, so the report says which. |
| Open ports | 80, 443 only — the origin serves no HTTP directly |
| Certificates | 11 in CT logs, 3 subdomains, issued by Google Trust Services |
| Email auth | SPF · DKIM · DMARC all present (DMARC at p=none — a
monitoring policy, not an enforcing one, and the report says so) |
| DNS integrity | DNSSEC signed and validating · CAA restricts issuance to 6 CAs |
Notice what this report does not do. It does not present 387 findings as if they were all
current. It does not mark the untested ones "resolved" to look good. It does not report a green
DMARC row when the policy is p=none. And it does not print "0 owned IPs" without
explaining that the number is correct. All four are easy to get wrong, and all four are how a
scanner loses your trust the first time you check its work.
Fifteen scans between 2026-07-10 and 2026-08-06, plotted from the same snapshot data the Evolution tab reads. The interesting signal is not the totals — it is which direction each line moves, and whether we can explain every step.
One of the fifteen snapshots recorded zero for every asset type — a partial run that indexed findings only. It is excluded from these lines rather than drawn as a crash to zero, because charting it would invent an outage that never happened.
try.h0sint.com and tease.h0sint.com being decommissioned.Every number above is rendered by the same data model the exports read — change the scan and all of them move together. That is the point of having one model rather than a dashboard and a report that drift apart.
The free scan is passive: it reads only what is already public, needs no credentials, no agent, and no access to your systems. It takes about a minute.
Scan my domain →