A Log Reader That Was Also a Credential Reader
July 26, 2026 · InfraScout Team
A security review of the authentication, multi-tenancy, and MCP surfaces turned up several findings. Two of them share a shape worth naming: a comment in the code claimed a protection that the code did not actually deliver.
The log reader had no path restriction
The cross-platform log reader reads a text file at a path you give it, narrows it with filters, and returns a bounded result. It cannot change anything, so it is classified read-only — and every role boundary in the product keys on that classification rather than on a list of tool names.
Which means it reached exactly the callers you would least want holding an unrestricted file reader. The standard user tier, which is denied a shell outright. Read-only delegated runs. Read-only chat. All of them could open any path the agent process could open — and the agent runs as LocalSystem on Windows and root on Linux.
For those callers that is not a log reader. It is fleet-wide credential disclosure: password hashes from the Windows account database, SSH and TLS private keys, cloud provider token caches, and — worst of the set — the agent's own certificate and private key, which on Unix is a plain file the agent must be able to read. Anyone who obtained that could impersonate the agent.
The accepted risk had been documented, but scoped to delegated runs only. The role gate, which keys on the read-only classification, had quietly extended it to the standard user tier as well.
The fix
A hard denylist of credential locations, refused outright. It is enforced in two places, and both matter for different reasons.
Before dispatch, on the server. A refusal there costs no execution and no round trip, and — critically — the protection is live for your entire fleet the moment this ships, rather than waiting for every agent to update.
At the point of reading, on the agent. So that every other path to a file read inherits the rule without anyone having to remember to add it.
Matching is done on a normalized path, segment by segment, rather than as a string prefix. That closes the variations that would otherwise slip a denied name past a rule: a drive letter, a UNC share, a shadow-copy path, a .. traversal. Two Windows-specific canonicalizations are applied because Windows performs them itself before opening a file, and either would otherwise smuggle a name through — an alternate-data-stream suffix on a hive name, and trailing dots or spaces on a filename. The check is also re-run against the resolved target of a symlink, since a planted link from a log directory to a credential file would otherwise pass a purely textual check and then present as an ordinary file.
The rule applies uniformly, to every caller and every role. An administrator has other, better ways to read a credential file on a host they administer; carving out an exception here would mean the control had a bypass, and a bypass that exists for one role is a bypass.
Two ways past the read-only PowerShell floor
The read-only PowerShell tool validates a script against a command policy before dispatch and blocks anything that would change host state. A deliberate attempt to get past that floor found three genuine false negatives — and because the tool is classified read-only, every one of them was a read-only caller able to mutate a host, which is privilege escalation rather than a policy gap.
The first two were the same underlying miss. PowerShell lets you write through a provider path as an assignment — ${C:\Windows\Temp\x.txt} = 'value' writes a file, and the environment-variable form does the same thing to a process variable. Neither is a command invocation, so none of the rules that examine command names, verbs, or redirections ever saw them. An arbitrary file write is an indirect path to code execution. A new rule now matches an assignment whose left-hand side is a drive-qualified variable path — keyed on the drive qualifier specifically, so ordinary comparisons and reads are unaffected.
The third was a plain omission: piping into a cmdlet that writes its input to a file, whose verb was not in the list of modifying verbs and whose name was missing from the file-write list. Added.
Rate limiting across the whole surface
Rate limiting covered some endpoints and not others. It now covers the surface as a whole.
Every rejection carries a retry indication, so a client that hits a limit backs off correctly instead of hammering. The authentication configuration endpoint and the OAuth callback have their own per-address shields, since both are unauthenticated by necessity. The OAuth client-registration and authorization endpoints are shielded tightly, being the paths where an attacker gets to make InfraScout do work before proving anything. Authenticated API traffic has a per-user limit applied after sign-in, so one account cannot crowd out the rest of a tenant. And a generous catch-all sits around everything else as a backstop — with health probes exempt, because rate-limiting a platform's own liveness check is a way to take yourself offline.
Client-side retry handling was added alongside, so a limit that does fire is usually invisible rather than an error somebody sees.
And one more, from the same review
A group-membership rule that matched on a regular expression was passing that expression through to the database's own matching engine. Rules are written by tenant admins rather than by attackers, so this was defense in depth rather than an active exposure — but a pattern reaching a database engine is a pattern you have handed considerably more power than matching. Regular expressions in group rules are now evaluated in the application, against an engine with predictable performance characteristics, so a pattern is a pattern and nothing more.
What you need to do
Nothing. All of it is server-side, and the log reader denylist in particular took effect across every agent the moment it shipped, without waiting for agent updates.
If your assessments read log files, the one visible change is that a path in a credential location now returns a refusal explaining itself. That is the control working. For what the log reader can and cannot open, see Agent Tools; for the trust model as a whole, see Security Architecture.
Questions, or a finding of your own to report? info@infrascout.cloud.