Skip to main content

secrets-infisical

Use when secrets reach an OpenClaw instance through an injection wrapper and something about that is in question — a feature silently off while the config looks right, an instance receiving far fewer keys than its siblings, a plaintext env file inside the state tree, a token or client id sitting in a backup or identity copy, a key that has to be added, rotated, or proven delivered, a machine identity or its project binding, a secret reference in the config, or a restart whose safety depends on every referenced key still resolving.

Source facts

Repository
Agents-Store/opencode-plugins
Last source activity
August 31, 2026 at 16:44
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
4 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
secrets-infisical
description
Use when secrets reach an OpenClaw instance through an injection wrapper and something about that is in question — a feature silently off while the config looks right, an instance receiving far fewer keys than its siblings, a plaintext env file inside the state tree, a token or client id sitting in a backup or identity copy, a key that has to be added, rotated, or proven delivered, a machine identity or its project binding, a secret reference in the config, or a restart whose safety depends on every referenced key still resolving.
# Secret injection and the store Secrets are not in the config. The config holds **references**; the wrapper resolves them at start. Everything here follows from that, including the failure that looks like a broken feature and is really a missing key name. ## Mechanics The gateway command is wrapped: the wrapper mints a **short-lived machine-identity token**, exchanges it for the project's secret set, and execs the real process with those values **in its environment only**. Nothing lands on disk, so: - Reading the config tells you what is *required*. Only running the wrapper tells you what is *delivered*. - An `exec` bypassing the wrapper sees no secrets and returns a false "key missing" verdict — which is why `ocexec.py` `hot` mode goes through the wrapper by default. - The identity is per instance, one file, mode 0600, owned by root (`fleet.secrets.identity-file-mode`). A wrong project or environment binding shows up as short delivery, never as an error. - Store values are **not encrypted at rest** — a recorded decision (`fleet.secrets.shared-store-plaintext`), not something to fix here. ## Never a value Presence, fingerprint (`fp:0000aaaa` — an obviously synthetic stub; a real one is eight hex digits of a digest), size bucket, key class, expiry date and full key name answer every operational question. The value answers none of them. - `redact.read_env_file` / `env_names` return names and fingerprints, never values. - `redact.structure_only` renders a credential document by shape — safe fields verbatim, identifying fields as fingerprints. That is also the token-sink detector: one account fingerprint across several credential directories. - Files that are **never read whole**: any env file, the auth-secret tree, auth profiles, credential directories, identity files, logs. Use a filter that structurally cannot return a value. - When a provider answers unauthorized the value is useless as evidence; presence, fingerprint parity with what is injected, and expiry are the whole answer. ## The delivery audit Two sets, compared **by name**: - **required** — every secret reference in the effective config, plus the names the compose file passes through. - **delivered** — the key names the wrapper actually produces inside the container. Names only; count the characters of a value if you need "non-empty", never print it. `required − delivered` non-empty is **critical**: the feature reading that key is dead and nothing logs an error (`fleet.secrets.delivery-short`). A count far below the siblings' is a wrong project or environment binding (`fleet.secrets.wrong-project`); a set of almost nothing is a broken identity (`fleet.secrets.identity-broken`). Compare against `secrets.expected_key_count` and against the other instances — a fleet of clones makes the outlier obvious. ## Restart precondition `compose restart` is R2, but on this deployment it carries an R3 precondition: **a running instance holds its secrets in memory; a restart re-resolves them.** Restarting while a reference no longer resolves converts a working instance into a dead one, and the cause is invisible afterwards. Run the delivery audit *before* any restart, show the resolved-name list in PRECHECK, and refuse while `required − delivered` is non-empty. ## Writing a secret Three leak paths, all closed at once, plus the one this plugin refuses outright. | Path | Why it leaks | Rule | |---|---|---| | command output | the write command prints the full `KEY=VALUE` table even in quiet mode | always discard stdout and stderr of the write | | process table | a value in argv is visible to every user on the box | pass by stdin or environment, never as an argument | | history and transcript | anything printed is on disk and in the model's context, permanently | **the plugin does not accept a key in chat** | The plugin prints the operator a line that reads the value with echo disabled, pipes it to the write, and then verifies by fingerprint alone. Overwriting a key whose fingerprint differs is red line `secret-overwrite-different-fingerprint` — a rotation, not an edit. Writes get zero retries (`gate.RETRY_RULES["secret-write"]`): a repeat risks a partial write and one more appearance in a process table. ## Identity login: capture stdout only The store CLI writes an update-check banner to **stderr**. A login that merges the streams glues that banner onto the token, every later call fails, and the error blames the credentials. Capture stdout alone — a token that "works by hand and fails in the script" is almost always this. ## Plaintext env files: parity decides, not existence A plaintext env file inside the state tree is either **redundant** (every key matches the store by fingerprint) or **load-bearing** (a key the store does not deliver). They look identical. **Deleting a load-bearing file takes the instance down at the next restart, silently.** Classify by fingerprint parity first, close the gap for load-bearing keys, then neutralise the file by **moving it to a quarantine path outside every container volume** — never `rm`. Red line `delete-plaintext-env`, finding `fleet.secrets.plaintext-env`; six-step procedure with its stop points and canary restart in `references/playbook.md`. ## A leaked value is not fixed by deleting the file If a token, client id or key ever sat in a file that left the box — a backup, a copy, a paste — the value is compromised, and removing the file removes the evidence rather than the exposure (`fleet.secrets.leaked-in-backup`, critical, R4). **Rotation is mandatory, not advisable.** Do not let the easy action stand in for the undone hard one: "removed the file" while the old value still authenticates closes the ticket without closing the exposure. ## Common mistakes - Reading the config and calling it delivery. - Running `exec` without the wrapper and concluding the key is missing. - Restarting before the delivery precheck. - Printing a value "just once" to compare it — compare fingerprints. - Deleting a plaintext env file because the store also has those keys, without checking every key. - Merging stderr into the login capture. - Treating a leak as filed once the file is gone. Procedures: `references/playbook.md`. Symptom to cause to check: `references/troubleshooting.md`. Repairs go through `/openclaw-ops:repair <selector> --issue <finding-id>`.
View on GitHub