70d812007f
- Environment audit and stack decision in build/agent_audit.md (Node + Electron shell over dependency-free core; deviation recorded) - Rewrite README/ARCHITECTURE/CONTRIBUTING for StepForge - Add SECURITY.md threat model, CODE_OF_CONDUCT.md, CHANGELOG.md, MPL-2.0 - Replace template grep checks with structural workflow check Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
70 lines
2.7 KiB
Markdown
70 lines
2.7 KiB
Markdown
# Security
|
|
|
|
## Offline Guarantee
|
|
|
|
StepForge ships with **zero network code paths**. The application:
|
|
|
|
- opens no sockets and performs no HTTP requests,
|
|
- has no telemetry, crash reporting, or analytics,
|
|
- performs no update checks and no license validation,
|
|
- has no account system, cloud sync, or remote AI integration,
|
|
- embeds no remote fonts, CDNs, or external references in exports.
|
|
|
|
The only network activity in the project's lifetime is the one-time
|
|
development fetch of the Electron shell via npm (see
|
|
`build/agent_audit.md`). The packaged app never goes online.
|
|
|
|
## Threat Model
|
|
|
|
Because the app is local-only, the realistic attack surface is **malicious
|
|
files opened by the user**:
|
|
|
|
### Archive imports (`.sfgz`, `.sfglt`)
|
|
|
|
Both formats are zip files. The reader in `core/zip.js` validates every entry
|
|
before extraction:
|
|
|
|
- entry names must be relative, must not contain `..` segments, drive
|
|
letters, or absolute paths;
|
|
- entries are extracted only beneath the destination directory (resolved
|
|
path is verified to stay inside it);
|
|
- file sizes are taken from actual inflated data, not trusted headers;
|
|
- unknown entries outside the documented layout are ignored.
|
|
|
|
### Image imports (PNG/JPEG/GIF)
|
|
|
|
Imported images are decoded by the platform image codecs in the Electron
|
|
shell and re-encoded to PNG before storage. The pure-JS PNG decoder in
|
|
`core/png.js` (used by exporters) rejects malformed dimensions, oversized
|
|
allocations, and bad CRCs.
|
|
|
|
### Linked guides and lock files
|
|
|
|
Shared `.sfgz` files opened in *linked mode* use a sidecar lock file
|
|
(`<name>.lock-sfgz`) containing the holder's machine name and timestamp.
|
|
This is an advisory lock for coordination on shared folders, **not** a
|
|
security boundary: a hostile or crashed peer can delete it. Conflicts are
|
|
surfaced to the user with keep-editing / discard options; the format is
|
|
last-write-wins and that risk is documented in the UI.
|
|
|
|
### Local data at rest
|
|
|
|
The guide store is **not encrypted at rest** — it inherits the user account's
|
|
filesystem protections, like any document folder. If you need encrypted
|
|
sharing, encrypt the `.sfgz` with external tooling; native encrypted archives
|
|
are a tracked enhancement, not a current feature.
|
|
|
|
## Renderer Hardening
|
|
|
|
The Electron renderer runs with `contextIsolation: true` and
|
|
`nodeIntegration: false`; the only privileged surface is the explicit
|
|
allowlisted IPC API in `app/preload.js`. Guide description HTML is sanitized
|
|
(allowlisted tags/attributes, no scripts, no event handlers, no external
|
|
URLs) before storage and again before rendering or export.
|
|
|
|
## Reporting
|
|
|
|
Report vulnerabilities by opening an issue marked `security` (this is a
|
|
local-only tool, so coordinated disclosure pressure is low; do not include
|
|
exploit archives directly — describe the structure instead).
|