Tools Learn Login Sign up
Blastline · Linux host sensor

Know what's there. Know what's open. Know what moved.

A one-way Linux agent that measures three things about a running web server — what it declares, what its apps can reach, and what moved — and writes unknown at full contrast for everything it cannot settle.

  • Scored against the Linux kernel: 0 false positives, 0 false negatives across the 3,130 queries it answered at high confidence — and it abstained on the other 812 rather than guessing.
  • No listening socket. bind()=0 listen()=0 connect()=1, measured with strace. It never opens a watched file.
One read-only pass · hourly, jittered shop.example.com · illustration, measured figures
  1. I what this server declares route_coverage partial
  2. II what the app's own OS user can reach 17 open / 100 closed / 0 unknown
  3. III what moved since the last pass 8 watched / 42 excluded
  4. IV where code could be placed 3 deny / 12 unknown

Four readings, one pass. The hatched share is what the evidence did not settle. It is reported at full contrast, not faded out and not rounded away — and readings I, III and IV come from different runs, so they are never added together.

How to read this page

We measure your server. We also publish what we couldn't measure.

Four states. Two of them are answers, and two of them are not — drawn differently on purpose, because colour alone would let an unanswered question pass for a clean one at a glance.

  • allow / high Settled. This principal reaches it. Solid fill.
  • deny / high Settled the other way. It does not. Solid fill.
  • unknown / abstain Asked, and deliberately not answered. Hatched, recessed, and never faded — an abstention is not a weaker answer, it is no answer, and it is not safe. It is drawn off the red/green scale entirely, because it is not a severity.
  • no evidence source Not asked, because this release cannot ask it. A step the engine has no way to compute on any host yet. Distinct from an abstention: an abstention means the question was put and did not settle here, this means the question cannot be put at all. Shown rather than hidden.
Four readings

One pass. Four readings. One OS user at a time.

Blastline does not ask what is wrong with your server. It asks four narrow questions it can answer from evidence on the disk, and it reports the share of each one it could not settle.

I

What this server declares

which vhosts, docroots, handlers and route mappings does this config actually resolve to?

Blastline reads the nginx and Apache configuration the way the webserver does — following nginx include directives rather than guessing — and builds the inventory of what is actually declared: server names, listen directives, document roots, aliases, FastCGI and proxy targets, try_files, deny_all, internal, directory listing, and the handler each route maps to. Every record carries its own provenance, so a docroot that was inherited is never presented as one that was declared.

This axis has no headline number, and that is the honest position: the inventory ships to us as counts per category, never as your raw routes. What it does publish is the shape of its own blind spots.

route_coverage: partial

route_coverage: partial means an include was seen and not followed — the config continues somewhere this pass did not go. directory_listing: unknown is a separate state from disabled, and the two are never merged.

What this does not say. It does not measure whether a route requires authentication — that is not parsed at all. HTTP methods are recorded only as "any" or "any except the ones declared", never enumerated. And reachability here is read from the listen and internal directives; the agent runs no probe from outside, so this is what the config says, not what the network does.
II

What the app's own OS user can reach

can principal P read, write or execute path X — along the whole path, not just the leaf?

This is the arithmetic the kernel runs, run deliberately. For each path and each principal Blastline resolves the POSIX mode bits, the principal's supplementary groups, and any POSIX ACL — including the mask:: entry, which silently narrows every named user and group entry and is the single most common source of a wrong answer in tools that skip it.

Traversal is resolved along the whole path rather than at the leaf: for a principal with no other route in, a file at 0644 inside a directory at 0700 it does not own is not reachable, and saying otherwise is a false positive. Results are reported per principal, not per endpoint — every endpoint running as the same user shares the same reach, so reporting it per endpoint would multiply one fact into a hundred.

17 100

117 queries on one live host — 17 reachable, 100 closed, 0 undetermined on this run, every one at high confidence. Among the reachable: .git/config, wp-config.php, .env. 0 undetermined is a result on this host; on one with an exotic filesystem or an unresolvable identity, it will abstain.

What this does not say. Those 17 are files the compromised app's own OS user can reach. They are not “publicly exposed” — and we will not tell you they are safe from the outside either, because their internet reachability was not measured. That is a different measurement, and the dashboard says the same thing on the screen you land on: site boundary is not yet measured.
III

What moved since the last pass

did anything appear, vanish, come back, or change how it would be handled?

Blastline does not scan your disk for changes. It watches only the slots the reach measurement already says something could be written into — a narrow, derived surface rather than a filesystem crawl — and compares it between hourly passes. On the measured host that meant 8 slots watched of 50 evaluated, the other 42 excluded because nothing could be placed there. Three consecutive runs produced zero noise.

It reports appeared, disappeared, modified, and — the one worth knowing about — reappeared, a file that came back after being removed. It also reports interpreter drift: became_executable and no_longer_executable, when the webserver's decision to run rather than serve a location changes underneath you.

8 42

8 watched, 42 excluded — from a separate 50-slot run to the one in axis IV; the two are never added together. Recursive coverage inside the watched roots measured 1,926 of 1,926 files. Detection is ctime_ns equality on stat metadata: the agent never opens the file.

What this does not say. There is no content hash and no integrity baseline — a change of bytes that leaves ctime untouched is not something this measures. It runs hourly with up to five minutes of jitter, so it is not real-time and it is not a filesystem watcher. And it will not notify you: Blastline sends no alerts today, in any channel. You read the result in the dashboard.
IV

Where code could be placed

could this slot carry executable code — W write, R reach, I interpret?

The sharpest case of axis II, and the one where abstention does the most work. Three legs have to hold at once: can this user write here, can anything outside reach the path, and would what lands there be interpreted as code. They combine under three-valued Kleene logic, where unknown ∧ allow is unknown and never allow. Nothing in the engine rounds an unresolved leg up to a conclusion, because a conjunction with a missing term is not a weaker claim — it is no claim.

The R leg is not signed in this release. Whether something outside can reach a given path is a question this version has no evidence source for, on any host, so it is reported as unknown rather than assumed in either direction — and that single missing leg is why the verdict below is what it is.

3 12
` strips the surrounding whitespace and glues the words together ("theexternal-reachability"), which is how this was broken once. -#}

15 slots evaluated on one host. By rung: no_path 3, insufficient_evidence 4, placement_path_exists 6, execution_likely 2. The sealed verdicts were {unknown/low: 12, deny/high: 3}not one allow/high, because the external-reachability leg was never observed.

  1. 6 execution_confirmed Something was seen running. no evidence source in this release
  2. 5 execution_likely Placed code would be handled as code. Reached by 2 slots — and still not a verdict.
  3. 4 externally_reachable Something outside can reach the path. no evidence source in this release
  4. 3 suspicious_change The watched surface moved. no evidence source in this release
  5. 2 placement_path_exists The user can write into the slot. Reached by 6 slots.
  6. 1 insufficient_evidence Asked, not settled. Reached by 4 slots.
  7. 0 no_path No placement path for this principal. Settled for 3 slots.

The rungs this engine can produce are a set, not a prefix. Three of the seven are struck through above because no version of this release can compute them, on any host — each needs an evidence source the agent does not have. A ladder that filled from the bottom would paint them as climbed. We would rather show you the holes.

What this does not say. A rung is not a verdict, and Kleene algebra will not round that up. We could have shipped “2 slots can host a web shell” from exactly this data. It would have been a better headline and a false one.
Measured, not asserted

Scored against the kernel

No heuristics, no scoring model, no machine learning — the decision procedure is small enough to audit, and it was checked against the only authority that cannot be argued with: the running Linux kernel on a real multi-user server, asked the same questions as the same principals.

Corpusgolden set, real server
3,942 queries — 146 paths × 9 principals × 3 access intents.
Agreement with the kernelpermission axis
3,130 / 3,130 — of the 3,942 queries the engine answered 3,130 at high confidence, and on every one of those it matched the kernel: 0 false positives, 0 false negatives. On the balance — 812 — it abstained. That is not 3,942 correct answers, and we will not round it up to one.
Object-identity oraclewas it reasoning about the right object?
0 mismatches. A separate axis, because a permission table can be silent while the engine reasons about the wrong node — two different objects can happen to share an answer. This oracle once found 400 such cases while the permission oracle reported zero. It is now clean.
Reason oracleis the stated reason the real one?
0 unfounded reasons across 2,020 denials — a right answer for a wrong reason is still a defect here, because the reason is what you act on.

Three independent axes, because the oracle you verify against decides which class of error you are able to see. A single axis returning zero is a comfortable result, not a settled one.

And every answer lands in one of three tiers — allow/high, deny/high, unknown/abstain. There is no fourth tier and no numeric score to hide behind. If the evidence does not settle the question, the answer is an abstention with a stated reason.

Stated limits

What Blastline does not claim

Not a disclaimer page and not fine print. These limits are the reason the numbers above can be trusted, so they are on the same page, at the same size, and none of them is behind a toggle.

01

We do not detect web shells

Blastline reports whether a slot could carry executable code. It does not scan for one, fingerprint one, or claim one is present. Reaching execution_likely means the placement path exists — it is a rung on an evidence ladder, not a verdict, and the engine keeps the two separate by design.

02

We do not prove external reachability

The R leg is unsigned in this release, and one class of case cannot be ruled out by this measurement even where it is. The product states it in its own output rather than in a footnote:

NOT PROVEN: (1) execution ("placement path exists" is not "it ran"); (2) the sealed rung does not change — this is not a ladder step; (3) the one mirror-proxy class this measurement cannot rule out: a byte-identical, mtime-preserved mirror copy served behind a proxy — in that case outside traffic may never reach the object on this disk at all.

03

We do not model root, the kernel, or privilege escalation

The threat model starts after the attacker can run code as the web application's user. Kernel exploits, EDR evasion, rootkits and local privilege escalation are out of scope. Blastline never assumes root and never reports on it. It measures one thing precisely rather than nine things approximately.

04

We tell you a credential is reachable, not what it unlocks

"This app can read that secret file" is measured. "That credential is an admin on your database" is a different question, requiring the credential to be used. It is off by default and lives behind an explicit opt-in, because access and power are not the same claim.

05

We cannot execute code on your agent — but we could blind it

The agent takes no commands. It parses exactly two things, both replies to requests it made itself: a schema-gated acknowledgement whose only decision-carrying bit is accepted, and a cryptographically signed rule bundle that can only adjust a threshold it already knows how to compute.

The honest boundary: a validly signed bundle could leave rules in place that can no longer fire. Countermeasures are a scope-regression gate, a staleness threshold, and a signature_health indicator in the dashboard — so a quiet agent looks quiet, not clean. This page previously would have said "the agent receives nothing"; that sentence was retired when it was measured and found to be too strong.

06

We abstain on ground we cannot stand on

The supported target is ext4 and XFS on a VPS. Blastline reads standard nginx and Apache configuration, including the configuration cPanel, Plesk and CloudPanel generate — but those panel adapters have not been verified against a live install, so we do not claim verified panel support. On an exotic filesystem, or where an identity will not resolve, Blastline returns unknown. Container-native layouts need a separate adapter and are not covered yet.

07

We do not send you alerts

Blastline has no notification channel at all today — no email, no webhook, no Slack. The agent pushes hourly and you read the result in the dashboard. The certificate and header monitoring elsewhere on this site does alert; the two products are not wired together yet, and we would rather say so than let the word "monitoring" imply it.

08

We do not find the way in

Blastline never looks for the vulnerability that gets an attacker onto your server. If you need boundary testing, that is what the SSL and header scanners on this site are for — different question, different tool, and Blastline sits alongside kernel-level and endpoint tooling rather than replacing any of it.

Data boundary

What leaves your server

The complete list, in both directions.

Never leaves the host

Not configurable, not opt-out, not negotiable.

  • File contents. Not transmitted — and on the watched surface, not even read: change detection compares stat metadata, so the file is never opened.
  • Secret values. The agent can report that a secret file is reachable without ever holding what is in it.
  • Raw logs. Parsed on the host; the parse result travels, the log does not.
  • Your route definitions. The endpoint inventory leaves as counts per category. The routes themselves stay on the host.

Does leave the host

Over outbound TLS, on a connection the agent opens itself.

  • Raw file paths. The full path, e.g. /var/www/shop/.env.
  • OS user names. The principal a finding belongs to, e.g. shop-fpm.
  • Metadata and verdicts. Modes, ownership, the decision and its stated reason. Plus an alias you choose for the server — the agent rejects the real hostname.
And the cost of that choice, stated plainly. Raw paths used to stay on the host too. That version of the product was unusable: an operator told "3 env files are readable" could not work out which file to fix. Sending the path fixes that, and it means if this portal were ever breached, an attacker would see your directory map and which files are open — the shape of an attack plan. We took that trade knowingly. If you see a page anywhere claiming raw paths never leave your server, it is out of date and it is wrong.
Setup

Install in five steps

One package, no third-party dependencies, any distribution with glibc 2.17 or newer. The exact commands, with your own activation key filled in, are on the setup page after you sign in.

1

Download the package

Debian, Ubuntu and RHEL. Published with a SHA-256 you can check before installing.

download on the server
curl -fsSLO https://myssl.info/downloads/myssl-agent_0.1.0_all.deb
2

Generate an activation key

Generated once and shown once, in the dashboard. It proves the agent's identity when it pushes from your server — it is not the REST API key from Settings, and the two are not interchangeable.

3

Install it

The two --force-conf* flags keep your agent.toml across upgrades; without them dpkg stops to ask an interactive question on every single one.

install
sudo dpkg --force-confdef --force-confold -i myssl-agent_0.1.0_all.deb
4

Pick the site and name the server

You make this choice on your own server, not here — the agent has to know what to scan before it has ever spoken to us. List what it found, then let it write the config block for you and delete the directories you do not want measured.

list sites, then generate the config block
sudo myssl-agent sites
sudo myssl-agent sites --toml

The block sets included_roots in /etc/myssl-agent/agent.toml. Without it the agent scans every site on the server, exceeds the free plan and is rejected. The alias is a label you choose; if it matches the machine's real hostname the agent refuses it and uses a safe per-install default instead.

5

Start it

The dashboard fills in on its own once the agent sends its first observation.

activate
sudo /usr/lib/myssl-agent/configure-egress
sudo systemctl start myssl-agent

Frequently asked questions

What does Blastline actually measure?

Three things about a running Linux web server, in one read-only pass. What the server declares: the vhosts, docroots, handlers and route mappings nginx or Apache actually resolve to. What each application can reach: for the OS user an app runs as, Blastline resolves POSIX mode bits, supplementary groups and POSIX ACLs including the ACL mask, along the whole path rather than just the leaf, and reports allow, deny or unknown. And what moved: on a deliberately narrow watched surface it compares file metadata between hourly passes and reports whether something appeared, disappeared, came back, or changed how it would be handled. Results are scoped to the principal, not to a single endpoint, because every endpoint running as the same user shares the same reach.

Is this a vulnerability scanner? Does it find webshells?

No, to both. Blastline assumes the compromise has already happened and measures the consequences; it does not look for the flaw that got the attacker in. And it does not detect web shells. It measures whether a slot could carry one — whether the user can write there and whether what lands there would be handled as code. Reaching the execution_likely rung means the placement path exists, not that anything was seen running. The third leg, whether something outside can reach the path, is not signed in this release and is reported as unknown rather than assumed either way.

Do my file contents or secret values leave my server?

No. File contents, secret values and raw logs stay on the host and are never transmitted. Blastline never opens a watched file at all: change detection compares stat metadata, not bytes. Raw file paths and the OS user names they belong to are sent, because without them an operator cannot tell which of three .env files to fix. That trade is deliberate and it has a cost: if the portal were breached, an attacker would see your directory map and which files are open. We would rather state that than hide it. Raw route definitions from your webserver config are not sent; only counts per category are.

Does the agent open a port or take commands from you?

It opens no port and binds no socket. Measured with strace: bind()=0, listen()=0, connect()=1 — outbound TLS only, so there is no listening socket for anything to connect to. It parses exactly two things, both replies to requests it made itself: a schema-gated acknowledgement whose only decision-carrying bit is accepted, and a cryptographically signed rule bundle that can adjust a threshold the agent already knows how to compute. A bundle cannot make it read a new file or take a new action.

So the server cannot do anything to my agent at all?

That would be an overstatement, so we will not make it. We cannot execute code on your agent, but a validly signed bundle could blind it — leaving rules in place that can no longer fire. The countermeasures are a scope-regression gate, a staleness threshold, and a signature_health indicator surfaced in the dashboard so a quiet agent looks quiet rather than clean. This is a stated boundary of the product, not a gap we discovered late.

What does unknown mean? Is unknown the same as safe?

No, and the difference is the point of the product. Every answer carries a confidence tier: allow/high, deny/high, or unknown/abstain. When the evidence does not settle a question — an exotic filesystem, an unresolvable identity, a leg this release does not sign — Blastline abstains rather than guessing. An unknown is an unanswered question, and it is drawn differently from a settled one everywhere in the interface, hatched rather than filled, so it cannot be misread as a clean result.

How do you know the answers are right?

They are scored against the Linux kernel itself on a real multi-user server. Across 3,942 queries — 146 paths by 9 principals by 3 access intents — the engine answered 3,130 at high confidence and agreed with the kernel on 3,130 of 3,130: no false positives, no false negatives. It abstained on the remainder rather than guessing. Two further oracles were run over the same corpus: object identity, meaning was it reasoning about the right object, returned 0 mismatches, and reason locality returned 0 unfounded reasons across 2,020 denials.

How often does it run, and will it alert me?

It runs hourly with up to five minutes of jitter, on a systemd timer. It is not real-time and it does not watch the filesystem continuously. Blastline sends you no notifications today — there is no alerting, no email and no webhook for it; you read the results in the dashboard. The MySSL certificate and header monitoring on the rest of this site does have alerting, but that is a separate product and the two are not wired together yet. A Linux server with glibc 2.17 or newer plus root to install the package is all it needs, and the free plan covers one site per server.

Build the map before you need it

Install the agent on one server, point it at one site, and read the inventory. Worth most if you host more than one site on a box, or if you have ever had to answer "how bad was it?" after an incident — and worth nothing at all if you wanted a tool that grades everything and explains none of it.

Requires a free MySSL account and root on the server you install it on. One site per server on the free plan. File contents and secret values never leave the host; raw file paths and OS user names do.

Report a bug

We're new and growing — your feedback helps us improve.

Click to upload, or paste (Ctrl+V) an image