mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
feat(webapp): refuse to share a file that looks like it holds credentials (BEA-111) (#137)
Minting a share link ran zero content checks: a file holding an AWS-shaped key became a public URL on one click, and the CLI printed nothing but the link. handleShareCreate now reads the first 1 MiB and runs six anchored rules between the synced-path check and Shares.Create, answering 409 with rule ids and line numbers unless the request carries confirm: true. The matched text never leaves scanSecrets — not into the body, not into a log line. TestShareSecretNeverEchoed greps both for the planted string, because a 409 body is the easiest place in this codebase to leak it. Both callers carry the override, since the gate alone would turn any false positive into a hard block with no way out: `bdrive share --force`, and the browser's Share-anyway dialog on modalConfirm (no new component). A path that already has a live link skips the scan — its content is public already, so withholding the URL protects nobody — but alreadyPublic drops links whose creator left the org, since those 404 at /s/ and would otherwise wave a secrets file straight through. A failed blob read is 503, not a silent pass: the repo's "degrade rather than fail" posture is for sync cycles, and a check that skips itself on a storage hiccup is the false confidence this exists to remove. Every user-facing string says the file was checked at the moment you shared it. A link serves the file's LATEST content forever, so a key written into an already-shared file is never caught — that open loop stays open, and the copy is the only thing stopping v1 from claiming otherwise. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
594a027c15
commit
d3d92bf904
@@ -91,8 +91,11 @@ scripts can't touch hub sessions and a scraper can't turn your hub into a CDN.
|
||||
|
||||
:::caution
|
||||
Any org member can mint links, and a link is public to whoever holds the URL.
|
||||
Don't put secrets in a synced folder. Note also that a LAN-bound hub means
|
||||
LAN-only links.
|
||||
Before minting, the hub scans the first 1 MiB of the file for
|
||||
credential-shaped strings and refuses (`--force`, or **Share anyway** in the
|
||||
UI, overrides it) — but that check runs *at the moment you share*, and a link
|
||||
serves the file's latest content forever, so don't put secrets in a synced
|
||||
folder. Note also that a LAN-bound hub means LAN-only links.
|
||||
:::
|
||||
|
||||
## Who wrote what
|
||||
|
||||
@@ -231,3 +231,12 @@ Regardless of configuration:
|
||||
the seeded default covers the common cases. But treat it as hygiene, not a
|
||||
security control: any org member can mint a public link for any synced file.
|
||||
Secrets belong in a secret manager, not in a folder you hand to agents.
|
||||
|
||||
Minting a share link is the one place the hub reads the bytes first: it scans
|
||||
the **first 1 MiB** for credential-shaped strings (AWS access key, private key
|
||||
block, GitHub/Slack/GitLab/OpenAI token) and refuses, naming the rule and the
|
||||
line but never the matched text. `bdrive share --force` — or **Share anyway**
|
||||
in the web UI — overrides it. Know what that check does *not* cover: it runs
|
||||
**at the moment you share**, and a link serves the file's latest content
|
||||
forever, so a key written into an already-shared file is never caught. It is a
|
||||
last-line backstop, not a reason to sync a folder you wouldn't otherwise.
|
||||
|
||||
@@ -20,7 +20,7 @@ One binary, `bdrive` — the CLI, the sync daemon, and the web server.
|
||||
| `bdrive grep <pattern> [folder]` | Search the text **inside** the files a project syncs. `pattern` is a Go RE2 regexp, or a literal string with `-F`. `-i` ignores case, `-l` prints matching paths only, `-n` caps the lines printed (default 200, `0` = all). Pure read: no daemon, no lock, no network |
|
||||
| `bdrive forget <path>...` | Stop syncing a path and remove it from the hub. Adds the rule to `.bdriveignore` (which syncs) and prunes in one step. Local files are never touched, here or on teammates' devices |
|
||||
| `bdrive url [path]` | Internal hub link for a file or folder — sign-in and membership required. `--sync` pushes first; no argument gives the project home. Computed locally |
|
||||
| `bdrive share <file>` | Public URL for a synced file. `--list`, `--revoke`, `--expires` (the hub's Share dialog can also set an expiry on an existing link) |
|
||||
| `bdrive share <file>` | Public URL for a synced file. `--list`, `--revoke`, `--expires` (the hub's Share dialog can also set an expiry on an existing link). Refuses a file whose first 1 MiB holds credential-shaped strings — `--force` shares it anyway |
|
||||
| `bdrive sync [folder]` | Run one sync cycle now. Refuses folders this device never `init`ed and folders paused by `bdrive stop`. `--note <text>` stamps session context onto changes; `--note-ttl` (default 30m) bounds it. `--prune` also removes from the hub what `.bdriveignore` now excludes (files stay on disk everywhere). `--hook <label>` is agent-hook plumbing |
|
||||
| `bdrive hooks [install\|uninstall]` | Register turn-boundary sync hooks in each detected agent platform's user config — once per machine, covering every folder. Run automatically by `bdrive init`; idempotent; `--agent` overrides detection. `uninstall` removes only BearDrive's own hook entries |
|
||||
| `bdrive read-log [folder]` | Hook plumbing: queue agent file reads for the hub's read heatmap. Registered by `bdrive hooks install` |
|
||||
|
||||
Reference in New Issue
Block a user