ssh, sftp, scp and rsync are not four ways to do the same thing. Each takes a different route through an SSH connection and therefore produces different statements — which is what decides whether a rule can see it.
Fencing a path
A rule never sees the client. It sees a statement, and tests itspattern_regex against that statement’s text. So the only question that matters is what string each route puts into that text.
The same file, fetched five ways:
The path survives into the text whichever route the client took — as the entire text on an
sftp_* operation, as a substring of a command line on exec_line. So one regex catches all five, provided operations names both families:
Compare rows 3 and 4 of the first table: the same
scp command, one flag apart, lands in a different family. Naming only one of them is a hole, not a style choice.
Scoping earns its keep in the other direction too: unscoped, this regex would also be tested against every env_set variable name and every other statement the lane produces.
sftp
File transfer is the one subsystem admitted by name, because its wire format frames one request at a time — open a path, read or write through a handle, remove, rename, create or list a directory, read attributes. That framing is what turns the subsystem was used into this path was read.sftp_read /home/devuser/data/customers.csv, not “a file was transferred”. The ten operations and what each matches against are in Configuration.
sftp requires the Sidecar process to be the account. File transfer is served inside the process — there is no child to hand a credential to — so a root listener cannot admit it. See Root vs non-root.Uploads
A file the connection reads back is safe to rewrite in place. A file it is writing is not: rewriting those bytes would silently corrupt what the user believes they uploaded. So an upload a masking rule would touch is refused, and nothing is written:scp
OpenSSH 9 changedscp’s default transport to the SFTP subsystem. -O selects the legacy one. Same file, same user, same result — two completely different policy surfaces:
-O run produces a single exec_line reading scp -f /home/devuser/data/customers.csv.
Both are masked. And a rule scoped across both operation families catches both:
operations list on a path rule must name exec_line and the sftp_* operations. A rule that names only one of them is bypassed by a flag.
rsync
rsync -e ssh runs a remote command, so it lands as one exec_line:
-e flag string encodes rsync’s own protocol negotiation and varies by version. What matters is that the path is in it, and so is the verb — so a guardrail fences rsync the same way it fences anything else:
Masking conflict
Audit trail
There is no setting that adds file content, on purpose: a setting that records nothing is the failure this design refuses everywhere else.
Known issues
Both are defects with fixes pending, not design. Knowing them stops you reading a failure as your own mistake.Next
Configuration
The ten
sftp_* operations, and why there is no sftp_open.Guardrail Rules
Every rule type, and the full operation vocabulary across protocols.