From ea17fcec3e7946b47d3de4a5a10b7f9157d16e54 Mon Sep 17 00:00:00 2001 From: Maurice Schmicking <17197791+mschmicking@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:42:12 +0200 Subject: [PATCH] docs: add a security policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub's template is a supported-versions table and a placeholder sentence, which tells a researcher nothing. This one names where the risk actually is — credential storage, the path guards that turn server-controlled ids into filenames, the auth and TLS handling — so someone looking has somewhere to start. It also records the deliberate trade-offs so they need not be re-reported: the stored password is a 0600 file rather than encrypted because there is no portable keychain, there is no --password flag because argv is readable via ps, allowSelfSigned accepts any certificate, and push is field-scoped by design. Response expectations are what one person in their spare time can actually meet, rather than an SLA that would be missed. Co-Authored-By: Claude Opus 5 --- README.md | 1 + SECURITY.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 SECURITY.md diff --git a/README.md b/README.md index fdf3736..f044574 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,7 @@ test -z "$(iob-sync --json status | jq -rc 'select(.state != "in-sync")')" - **[AGENTS.md](AGENTS.md)** — architecture, wire protocol, safety invariants. Written for AI coding agents, but the fastest way for a human to understand the codebase too. - **[CHANGELOG.md](CHANGELOG.md)** — release history +- **[SECURITY.md](SECURITY.md)** — how to report a vulnerability, and the deliberate trade-offs ## License diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..8944195 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,73 @@ +# Security policy + +`iobroker-sync` connects to a live ioBroker instance with credentials and writes files +derived from server-controlled identifiers. Security reports are welcome. + +## Reporting a vulnerability + +**Please do not open a public issue.** Use GitHub's private reporting: + +**[Report a vulnerability](https://github.com/mschmicking/iobroker-sync/security/advisories/new)** +— Security → Advisories → Report a vulnerability. + +This is a spare-time project maintained by one person. Realistic expectations: + +- Acknowledgement within about a week. +- A fix for anything that exposes credentials or writes outside the script root gets + priority over everything else. +- I will tell you plainly if I think something is not a vulnerability, and why. + +Credit in the advisory and the changelog if you would like it. + +## Supported versions + +| Version | Supported | +| -------------- | ------------ | +| latest `1.x` | ✅ | +| anything older | ❌ — upgrade | + +Fixes ship as a new release rather than as patches to old versions. + +## Where the risk actually is + +If you are looking for somewhere to start: + +- **`src/credentials.ts`** — password storage. Written to + `~/.config/iobroker-sync/credentials.json`, mode `0600` in a `0700` directory, via + temp-file-and-rename. +- **`src/sync/safe-path.ts`** — server-controlled ioBroker ids become local file paths. + Guards against traversal, symlinked files and symlinked directories. +- **`src/client/auth.ts`** — OAuth2 and legacy login, TLS handling. +- **`src/commands/backup.ts`** — snapshots contain whatever secrets the live scripts do, + and land under the gitignored `.iobroker-sync/`. + +## Deliberate decisions that are not bugs + +These are known trade-offs, documented so they need not be re-reported: + +- **The stored password is not encrypted.** It is a `0600` file in a `0700` directory + outside the project. There is no portable OS keychain across Linux, macOS, Windows and + Termux, and the realistic alternative — an environment variable — is worse: it leaks + into shell history and into the environment of every child process. +- **There is no `--password` flag.** `argv` is readable by any local process via `ps` and + is recorded in shell history. Use `--password-stdin`, `IOBROKER_PASSWORD`, the saved + credential, or the interactive prompt. +- **`allowSelfSigned` accepts any certificate.** It exists because ioBroker refuses + passwords over plain HTTP, so authenticated instances are HTTPS with a self-signed + certificate. There is no certificate pinning; on an untrusted network, that is a + meaningful limitation. +- **`push` cannot disable a script or move it between javascript instances.** It sends + only `common.source` and `common.engineType`, enforced by the type of + `ObjectsApi.extendScript`. This is a safety property, not an oversight. +- **Test fixtures contain password-shaped strings.** All fake — `secret`, + `correct horse battery staple`, `fake-oauth-token`. + +## What is genuinely worth reporting + +- Anything that writes outside the configured script root. +- Anything that puts a password into a log line, an error message, `argv`, or the project + directory. +- Anything that makes `push` write a field other than `common.source` and + `common.engineType`. +- Anything that lets a malicious ioBroker server cause local code execution or + arbitrary file writes.