Cortex is a privately developed tool, so it will arrive as a built artifact rather than as
something you assemble yourself. That artifact does not exist yet, and this section is careful
not to imply otherwise.
Today
Nothing to install
There is no download. No binary has been produced, signed or published anywhere, and the
engine does not yet build cleanly at the commit this page is written against.
Everything on this page is therefore documentation and recorded evidence rather than a
product you can run. When that changes, this section changes with it, and the capability
register below will move first.
Target v1 distribution
Planned
One signed executable per platformLinux, macOS and Windows on amd64 and arm64, published with checksums and signatures.
No data directory, no runtime dependencyThe fingerprint database is compiled in, so a fresh machine needs nothing else present.
No privileges for the default scanConnect, TLS and HTTP observation need no elevation anywhere. Raw sockets stay opt-in.
Nothing phones homeNo account, no licence server, no telemetry. The scan store stays on the machine that produced it.
A claim is a summary of some bytes. Keep the bytes.
Scanners tell you a port is running nginx. Almost none of them can still show you the response that made
them say so, because the moment the process exits, the reasoning is gone.
Cortex writes every probe exchange to a content-addressed store: the exact payload sent, the exact bytes
received, the pattern that matched and where it matched, the version of the fingerprint database that
supplied it, and a SHA-256 over the response.
A finding then references that hash rather than restating a conclusion. False positives become diagnosable
instead of mysterious, results become auditable, and the captured responses become the regression corpus
that keeps fingerprinting honest as it grows.
Recorded fixture
Illustrative recorded-format fixture for the finished Cortex model, from a purpose-built lab network. Not
output from today's engine. Open a row to descend from the claim to the bytes.
10.20.0.7:22/tcpOpenSSH 9.6p1confidence 96probe 0 B sent
/ 23 B received
Sentprobe NULL / 0 bytes
The NULL probe sends nothing. It waits to see whether the service speaks
first, which is itself evidence.
Received 23 bytes
Response received from 10.20.0.7:22/tcp. The span highlighted and underlined is the text the fingerprint
pattern matched.
The hash shown on each record is the real SHA-256 of the bytes displayed above it. Copy the response out of
the page and hash it yourself if you want to check.
One probe, end to end
This is the whole detection path for the record in the hero, in the order it happens, with what exists in
the engine today marked against each step.
01 Select
Probes are chosen by port and by rarity rather than tried in file order, so a filtered port cannot occupy a worker for minutes.
probe GetRequestPlanned
02 Send
The probe payload goes out on its own connection. Reusing one socket for every probe is what makes most hand-rolled scanners produce nonsense after the first response.
18 bytes outIn development
03 Receive
The response is read under a deadline derived from a measured round-trip estimate, capped, and kept verbatim. Binary stays binary.
296 bytes inIn development
04 Match
Patterns come from a parsed service-probe grammar with dynamic delimiters and escape normalisation. Constructs Go regexps cannot express are recorded as unsupported, not silently counted as parse failures.
offset 25, length 12In development
05 Extract
The version template turns the capture groups into product, version and extra information, with a confidence value and the method that produced it.
nginx 1.27.2, confidence 98Planned
06 Record
The response is stored by content address, de-duplicated across hosts, and the claim keeps a reference to it rather than a copy of it.
sha256:86319f1a…37c7c4Planned
The parser that reads the probe grammar is the oldest real code in this project and the reason it exists.
Everything marked planned above is designed and unbuilt, and the engine does not compile at its current
commit.
The second scan is the useful one
Nobody runs a scanner once. Cortex keeps every scan as a structured record, so the question it can answer
on the second run is not what is open, but what moved.
Recorded fixture
Illustrative recorded-format fixture for the finished Cortex model, from a purpose-built lab network. Not
output from today's engine.
01JQ7WA9F1 tocompared with 01JQ7XR4K2 10.20.0.0/245 changes
10.20.0.33:6379/tcpopenedRedis key-value store 7.2.5
Previous
Not present in this scan.
Current
Redis key-value store 7.2.5 no authentication required
Replaced one day after the previous certificate expired. Still self-signed.
10.20.0.42:21/tcpclosedvsftpd 3.0.5
Previous
vsftpd 3.0.5
Current
No longer present. Now answering with a connection refusal.
Now answering with a connection refusal.
142 subjectsunchangedno movement
Ports, services, certificates and evidence hashes that were byte-identical across both scans.
Collapsed by default so that the five rows above are the whole of what a reader has to look at.
They are not enumerated in this fixture.
The local interface
Cortex is a command-line tool that can serve a local viewer over its own scan store, bound to loopback,
for the times when a table beats a terminal. This is that viewer, running on the recorded fixture.
Recorded fixture
Illustrative recorded-format fixture for the finished Cortex model, from a purpose-built lab network. Not
output from today's engine. Nothing here contacts a network. Selection and view switching happen in the page.
Hosts against ports. Each cell states the port state in its accessible name.
Address
21
22
25
80
443
5432
6379
8443
10.20.0.7
10.20.0.7 port 21: not in this scan
10.20.0.7 port 25: not in this scan
10.20.0.7 port 443: not in this scan
10.20.0.7 port 5432: not in this scan
10.20.0.7 port 6379: not in this scan
10.20.0.7 port 8443: not in this scan
10.20.0.11
10.20.0.11 port 21: not in this scan
10.20.0.11 port 25: not in this scan
10.20.0.11 port 80: not in this scan
10.20.0.11 port 443: not in this scan
10.20.0.11 port 6379: not in this scan
10.20.0.11 port 8443: not in this scan
10.20.0.14
10.20.0.14 port 21: not in this scan
10.20.0.14 port 22: not in this scan
10.20.0.14 port 25: not in this scan
10.20.0.14 port 80: not in this scan
10.20.0.14 port 5432: not in this scan
10.20.0.14 port 6379: not in this scan
10.20.0.21
10.20.0.21 port 21: not in this scan
10.20.0.21 port 22: not in this scan
10.20.0.21 port 80: not in this scan
10.20.0.21 port 443: not in this scan
10.20.0.21 port 5432: not in this scan
10.20.0.21 port 6379: not in this scan
10.20.0.21 port 8443: not in this scan
10.20.0.33
10.20.0.33 port 21: not in this scan
10.20.0.33 port 22: not in this scan
10.20.0.33 port 25: not in this scan
10.20.0.33 port 80: not in this scan
10.20.0.33 port 443: not in this scan
10.20.0.33 port 5432: not in this scan
10.20.0.33 port 8443: not in this scan
10.20.0.42
10.20.0.42 port 22: not in this scan
10.20.0.42 port 25: not in this scan
10.20.0.42 port 80: not in this scan
10.20.0.42 port 443: not in this scan
10.20.0.42 port 5432: not in this scan
10.20.0.42 port 6379: not in this scan
10.20.0.42 port 8443: not in this scan
open
closed
filtered
not in this scan
Excluded from this design on purpose: summary tiles, a chart wall, and anything resembling threat
intelligence. A scan is not a business metric, and a viewer for one should stay an instrument.
How a scan is put together
Seven stages in a line, and four concerns that cut across all of them. The four are the reason the seven
can be trusted, and they are where most hand-rolled scanners quietly have nothing.
02Expanderlazy iterator, deduplicated, shuffled from a recorded seed
03Discoverywhich hosts answer, and by what reason
04Port scanconnect by default, raw sockets only when asked
05Protocol detectprobe selection, match, version extraction
06EnrichmentTLS chain and HTTP surface, observed not judged
07StoreSQLite records, evidence by content address
Scheduler
A token bucket in probes per second, plus a separate ceiling on how many can be in flight, plus a per-host cap so no single machine takes the whole scan at once.
Progress
One event stream consumed by the terminal renderer, the local viewer and the machine-readable output, so all three see the same scan.
Cancellation
A cancelled scan flushes what it already found, records where it stopped, and can be resumed from that position.
Evidence
Every stage that touches the network writes what it saw, capped and content-addressed, before anything interprets it.
One process. No broker, no queue service, no database server, no container required. The finished tool is a
single binary that holds the engine, the fingerprint database, the store and the viewer.
Restraint, as a feature
Aggressive defaults are easy to build and hard to live with. These are the constraints the finished tool is
designed around, and most of them cost throughput on purpose.
Unprivileged by default
Connect scanning, TLS observation and HTTP observation need no elevation on any platform. That path is what most people should ever use, and it is the default.
Privileged mode is explicit, and never silent
Raw sockets are opt-in. Asking for a SYN scan without the capability fails with the exact command needed to grant it, rather than quietly falling back to a different scan that produces different results.
Privileges are dropped before hostile input is read
Raw handles are acquired at startup, then the process drops to the invoking user. Parsing whatever a target chooses to send back happens unprivileged, because that parser is the largest attack surface in a scanner.
Rate control is on by default
A token bucket, a concurrency ceiling and a per-host cap, with conservative defaults and adaptive backoff when a target starts rate-limiting. A scanner that cannot be slowed down is a liability on someone else network.
Large scans have to be confirmed
Past a threshold, a scan prints the computed host count, probe count and estimated duration and waits. Accidentally scanning a /8 should take more than one typo.
Local failures are never reported as target states
No route, permission denied and file descriptor exhaustion are scan errors with their own class. Reporting them as filtered is silent data corruption, and it is the single most common defect in this category.
Evidence is treated as sensitive
Captured responses will contain credentials sooner or later. The store is written owner-only, known credential patterns are redacted before persistence with the redaction recorded, and reports can be exported redacted.
Read-only interactions, permanently
Probes send the bytes a legitimate client would send. No exploitation, no brute forcing, no fuzzing, no denial of service, no evasion features. This boundary is not a phase, it is the product definition.
Against nmap, honestly
Nmap is the reference implementation of this entire category and it wins most of these rows. Cortex is not
trying to replace it. It is trying to answer a different question about the same network.
nmapCortex
OS fingerprinting
nmap is better
Around 2,600 curated fingerprints built on sixteen carefully sequenced probes, with two decades of community submissions behind them.
None. Not in the plan either: one person cannot build that corpus, and pretending otherwise would waste the years it would take.
Scripting
nmap is better
NSE, roughly six hundred scripts and the community that maintains them.
No scripting. If it ever arrives it will be sandboxed and narrow, and it will not be a plugin ecosystem.
Raw packet handling
nmap is better
Correct link-layer framing, ARP, routing, fragmentation and IPv6, hardened across a dozen operating systems.
The current raw path is structurally wrong and is being rewritten. The unprivileged path comes first because it is what most scans need.
Portability and field testing
nmap is better
Twenty-five years of platform work. It runs where you need it and it has been wrong in public often enough to be right now.
Three platforms are targeted. Zero releases exist. Nothing here has been field tested by anyone.
Speed
different goals
Adaptive timing, retransmission and congestion control. For pure throughput, masscan and its relatives are faster still.
Not competing. No throughput number has been measured, so none is published, and that race is already won by other tools.
Change between scans
different goals
ndiff compares two saved XML files and reports host and port differences.
Diff is a verb over a persistent store, so it can also compare evidence hashes, certificate rotation and version movement, not only presence.
Machine-readable output
Cortex is designed better
XML designed in 1997, which every consumer wraps in a parser library. There is still no JSON output upstream.
JSON and JSONL from the first line, schema-versioned and deterministically ordered so two runs can be compared byte for byte.
The bytes behind a claim
Cortex is designed better
Debug output is unstructured text on a terminal, and it is gone when the process exits.
Every probe exchange is stored by content address and referenced by the claim it supports. This is the reason the project exists.
Distribution
Cortex is designed better
Installed from a package, with a data directory alongside it, and available on essentially every platform you might already be standing in front of.
Targets one signed executable with the fingerprint database compiled in, so a fresh machine needs nothing else. Nothing is published yet.
Four rows to nmap, three to Cortex, two that are not the same question. A comparison table where one column
wins everything is an advertisement, not information.
What is actually built
Nothing on this page is a released capability. At commit eabc16d the
engine does not compile, there are no tests, and no binary has ever been published.
This site describes the tool Cortex is designed to be. It exists ahead of the engine on purpose, as the
specification the engine is being built against. Every screen you have scrolled past is driven by an
authored fixture in the finished data format, and every one of them says so on the object itself.
Cortex is developed privately, so nobody can check these claims against the source. That is exactly why the
register below is written the way it would have to be written if they could: every row states what is
actually there, including the parts that are wrong or missing.
Available today 0In development 6Planned 14
Capability status against the current codebase
Capability
Status
What exists today
TCP connect scanning, three-state classification
In development
Implemented, including the pre-read that separates a reset from a timeout. Not release quality.
Service-probe grammar parser
In development
The oldest real code here. Dynamic delimiters, escape normalisation, and constructs Go regexps cannot express recorded as unsupported rather than as failures. Soft matches and fallback chains are not handled.
Probe selection by port and rarity
Planned
The rarity, ports and sslports directives are parsed and discarded, so every probe is tried in file order.
Probe exchange and banner capture
In development
Probes run, but all of them share one connection and the first response of any kind wins. A name is extracted; product, version, extra information and CPE are not.
Plain text and JSON output
In development
Both exist. Ordering is not deterministic yet, which is a prerequisite for diff.
SYN scanning
In development
Present and structurally wrong: a capture handle per port, no link-layer framing, no retransmission. Scheduled for rewrite, and it may be deferred past the first release.
UDP scanning
In development
Sends a single null byte. The parsed UDP probe corpus is loaded and never used.
Product and version extraction
Planned
Designed. The version template parser is an open task in the engine.
TLS and HTTP observation
Planned
Designed. Nothing imports a TLS library today.
Content-addressed evidence store
Planned
Designed. This is the centre of the product and none of it is built.
Scan store, list and show
Planned
Designed against SQLite. Today results are held in memory or in a Redis instance that is being removed.
Diff between scans
Planned
Designed. Depends on the store and on deterministic ordering.
Rate limiting, concurrency ceilings, cancellation
Planned
Designed. The current engine has none of the three, which is its most dangerous property.
Host discovery
Planned
Designed. Every listed host is currently assumed to be up.
Designed as verbs. Today the binary takes positional arguments and switches to server mode on a raw string match.
Local viewer, cortex ui
Planned
Designed, and previewed on this page from a fixture. The interface built so far is a mock that never contacts an engine.
Single binary with embedded fingerprints
Planned
Designed. The binary currently refuses to start without an external data file that is not shipped.
Released, signed binaries
Planned
None exist. No installation path is published anywhere.
Reference documentation and changelog
Planned
Neither exists. This page is the only current documentation, and it is written by hand.
Automated tests
Planned
There are none. Zero, of any kind.
No performance figure appears anywhere on this site, because no measurement of any kind exists yet. When a
benchmark harness is published, the numbers will arrive with the hardware, the settings and the commit that
produced them, and with the cases where nmap is faster.
Technical reference
Cortex is developed privately, so this page is its documentation rather than a summary pointing
elsewhere. Each entry below is a section of it, written to be read by someone deciding whether
the engineering is sound.
Planned
A versioned reference and a changelog, once there is a release to describe. Until then this page
is kept current with the engine rather than left to drift.