PerfLens puts an agent on a device and lets a server drive it. This document says what that protects and — more importantly — what it does not.
Use GitHub private security advisories rather than a public
issue. Include the version (perflens-agent --version, perflens version),
how the agent was launched, and what an attacker would need to reach.
What is protected. A peer must prove knowledge of a shared secret before the agent will run any command. Without it the agent will not start profiling, will not enumerate processes, will not stream device metrics, and will not update itself.
What is not protected: the channel. The wire protocol is plaintext TCP. There is no encryption, no integrity protection, and no defence against an attacker who can read or modify traffic between the server and the agent. The pairing code itself travels server → agent in the clear.
That is a deliberate trade for a tool aimed at controlled networks — lab benches, test racks, a device on your desk. If the network between you and the device is not trusted, tunnel it:
# On the device
perflens-agent --listen --bind 127.0.0.1
# On your machine
ssh -N -L 9999:127.0.0.1:9999 user@device
# then point the Live Debug wizard at 127.0.0.1:9999Profiling data is sensitive. A profile carries function names, source file
paths, stack traces and — with list_processes — the full command line of
every process on the device. Command lines routinely contain secrets. Treat a
saved session the way you would treat a core dump.
The agent always holds a secret:
--token SECRET/PERFLENS_TOKEN, if you supply one.- Otherwise, in
--listenmode, it generates a pairing code at startup — 16 random bytes from/dev/urandom, printed to its log — and the operator copies it into the server. There is no unauthenticated state to fall into.
The code is per agent start. Restarting the agent rotates it.
agent → server flag 3 {"type":"hello","version":1,"auth":"token",
"agent_version":"0.10.0","platform":{...}}
server → agent flag 2 {"id":"<hex12>","cmd":"auth","args":{"token":"<code>"}}
agent → server flag 3 {"id":"<hex12>","ok":true}
or {"id":"<hex12>","ok":false,"error":"auth failed"}
The hello carries no secret. It is sent to whoever completed the TCP
handshake, before that peer has proved anything, so everything in it is public
by construction. Until the exchange succeeds, every command is answered
{"ok":false,"error":"unauthenticated"}, and no metrics are streamed.
Three wrong codes, or 30 seconds without a valid one, and the agent drops the connection and returns to listening.
The agent normally runs detached, so read it from wherever its output went:
ssh user@device 'grep -i "pairing code" /tmp/agent.log'/proc/<pid>/cmdline is world-readable, and PerfLens's own list_processes
reports it. A secret passed as --token is visible to every local user; one
passed via PERFLENS_TOKEN is not. A generated pairing code never appears
in argv at all, which is the safest of the three.
--listen binds 0.0.0.0 by default, because reaching the device from
another machine is the point. Narrow it with --bind 127.0.0.1 (plus an ssh
tunnel) when you want the port unreachable from the network.
perflens serve binds 127.0.0.1 by default and the UI has no login. Anyone
who can reach the HTTP port can drive a connected agent and read every saved
session.
Do not pass --http-bind 0.0.0.0 on a shared or untrusted network. Use an
ssh tunnel to the server instead:
ssh -N -L 8080:127.0.0.1:8080 user@server--token protects the agent connection. It does not protect the HTTP port.
perflens-agent --update downloads a binary from the project's GitHub
releases over HTTPS and replaces itself. Two things worth knowing:
- The
--versioncheck is not integrity verification. The agent runs the downloaded binary and looks forperflens-agentin its output. That catches a wrong-architecture or truncated download. It does not catch a hostile one — by then the binary has already executed. - Checksums are published, and verified by the installers, not the agent.
Each release asset ships a
.sha256sidecar.install-agent.shandperflens push-agentverify it; the C agent does not, because it carries no hash implementation and will not grow one just for this. A sidecar served from the same origin as the asset stops truncation, corruption and a poisoned single object. It does not stop an attacker who controls the origin.
update is refused on a session with no configured pairing code. To update a
tokenless agent, use ssh:
ssh user@device '~/.perflens/bin/perflens-agent --update'Setting PERFLENS_UPDATE_URL to an http:// origin is refused outright.
Agents before 0.10.0 put their shared secret in the hello frame — which,
in --listen mode, meant handing it to anyone who completed a TCP handshake.
A 0.10.0 server still accepts such an agent when the token matches, logs a
warning, and strips the token before the hello reaches the HTTP API. Upgrade
those agents.
Upgrade order: server first, then agents. A 0.10.0 agent sends no hello
token, so an older server configured with --token will reject it.
| Version | Change |
|---|---|
| 0.10.0 | Pairing-code authentication. Legacy hello tokens accepted with a warning. |
| 0.11.0 | Legacy hello tokens refused when the server has a token configured. |
| 1.0.0 | A pairing code is required for both --listen and --server; only headless --output runs without one. |
Fixes land on the latest release. There are no backports to earlier lines.