Commit Graph

12 Commits

Author SHA1 Message Date
Aaron D. Lee
2629aabcc5 Fix 12 security findings from adversarial audit
Some checks failed
CI / typecheck (push) Waiting to run
CI / lint (push) Has been cancelled
CRITICAL:
- #1+#2: Consistency proof verification no longer a stub — implements
  actual hash chain reconstruction from proof hashes, rejects proofs
  that don't reconstruct to the expected root. GossipNode._verify_consistency
  now calls verify_consistency_proof() instead of just checking sizes.
- #3: Remove passphrase.lower() from KDF — was silently discarding
  case entropy from mixed-case passphrases. Passphrases are now
  case-sensitive as users would expect.
- #4: Federation gossip now applies record_filter (trust store check)
  on every received record before appending to the log. Untrusted
  attestor fingerprints are rejected with a warning.
- #5: Killswitch disables all logging BEFORE activation to prevent
  audit log from recording killswitch activity that could survive an
  interrupted purge. Audit log destruction moved to position 4 (right
  after keys + flask secret, before other data).

HIGH:
- #6: CSRF exemption narrowed from entire dropbox blueprint to only
  the upload view function. Admin routes retain CSRF protection.
- #7: /health endpoint returns only {"status":"ok"} to anonymous
  callers. Full operational report requires authentication.
- #8: Metadata stripping now reconstructs image from pixel data only
  (Image.new + putdata), stripping XMP, IPTC, and ICC profiles — not
  just EXIF.
- #9: Same as #6 (CSRF scope fix).

MEDIUM:
- #11: Receipt HMAC key changed from public upload token to server-side
  secret key, making valid receipts unforgeable by the source or anyone
  who captured the upload URL.
- #12: Docker CMD no longer defaults to --no-https. HTTPS with
  self-signed cert is the default; --no-https requires explicit opt-in.
- #14: shred return code now checked — non-zero exit falls through to
  the zero-overwrite fallback instead of silently succeeding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:31:03 -04:00
Aaron D. Lee
fef552b9c1 Fix 3 architectural bottlenecks blocking cross-domain adoption
Some checks failed
CI / lint (push) Failing after 58s
CI / typecheck (push) Failing after 32s
Bottleneck 1: ImageHashes generalization
- phash and dhash now default to "" (optional), enabling attestation
  of CSV datasets, sensor logs, documents, and any non-image file
- Added ImageHashes.from_file() for arbitrary file attestation
  (SHA-256 only, no perceptual hashes)
- Added ImageHashes.is_image property to check if perceptual matching
  is meaningful
- Added content_type field to AttestationRecord ("image", "document",
  "data", "audio", "video") — backward compatible, defaults to "image"
- from_dict() now tolerates missing phash/dhash fields

Bottleneck 2: Lazy path resolution
- Converted 5 modules from eager top-level path imports to lazy
  access via `import soosef.paths as _paths`:
  config.py, deadman.py, usb_monitor.py, tamper.py, anchors.py
- Paths now resolve at use-time, not import-time, so --data-dir
  and SOOSEF_DATA_DIR overrides propagate correctly to all modules
- Enables portable mode (run entirely from USB stick)
- Updated deadman enforcement tests for new path access pattern

Bottleneck 3: Delivery acknowledgment chain records
- New CONTENT_TYPE_DELIVERY_ACK = "soosef/delivery-ack-v1"
- ChainStore.append_delivery_ack() records bundle receipt with
  sender fingerprint and record count
- import_attestation_bundle() auto-generates ack when chain store
  and private key are provided
- Enables two-way federation handshakes (art provenance, legal
  chain of custody, multi-org evidence exchange)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 21:27:15 -04:00
Aaron D. Lee
9431033c72 Implement 7 real-world scenario features (Round 4)
Some checks failed
CI / lint (push) Failing after 52s
CI / typecheck (push) Failing after 30s
1. Source drop box: token-gated anonymous upload with auto-attestation,
   EXIF stripping, receipt codes, and self-destructing URLs. New
   /dropbox blueprint with admin panel for token management. CSRF
   exempted for source-facing upload routes.

2. Investigation namespaces: attestation records tagged with
   investigation label via metadata. Log view filters by investigation
   with dropdown. Supports long-running multi-story workflows.

3. Scale fixes: replaced O(n) full-scan perceptual hash search with
   LMDB find_similar_images() index lookup. Added incremental chain
   verification (verify_incremental) with last_verified_index
   checkpoint in ChainState.

4. Deep forensic purge: killswitch now scrubs __pycache__, pip
   dist-info, pip cache, and shell history entries containing 'soosef'.
   Runs before package uninstall for maximum trace removal.

5. Cross-org federation: new federation/exchange.py with
   export_attestation_bundle() and import_attestation_bundle().
   Bundles are self-authenticating JSON with investigation filter.
   Import validates against trust store fingerprints.

6. Wrong-key diagnostics: enhanced decrypt error messages include
   current channel key fingerprint hint. New carrier_tracker.py
   tracks carrier SHA-256 hashes and warns on reuse (statistical
   analysis risk).

7. Selective disclosure: ChainStore.selective_disclosure() produces
   proof bundles with full selected records + hash-only redacted
   records + complete hash chain for linkage verification. New
   `soosef chain disclose -i 0,5,10 -o proof.json` CLI command
   for court-ordered evidence production.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 20:41:41 -04:00
Aaron D. Lee
7967d4b419 Implement 7 field-scenario feature requests
Some checks failed
CI / lint (push) Failing after 51s
CI / typecheck (push) Failing after 29s
1. Transport-aware stego encoding: --transport flag (whatsapp/signal/
   telegram/discord/email/direct) auto-selects DCT mode, pre-resizes
   carrier to platform max dimension, prevents payload destruction
   by messaging app recompression.

2. Standalone verification bundle: chain export ZIP now includes
   verify_chain.py (zero-dep verification script) and README.txt
   with instructions for courts and fact-checkers.

3. Channel-key-only export/import: export_channel_key() and
   import_channel_key() with Argon2id encryption (64MB, lighter
   than full bundle). channel_key_to_qr_data() for in-person
   QR code exchange between collaborators.

4. Duress/cover mode: configurable SSL cert CN via cover_name
   config (defaults to "localhost" instead of "SooSeF Local").
   SOOSEF_DATA_DIR already supports directory renaming. Killswitch
   PurgeScope.ALL now self-uninstalls the pip package.

5. Identity recovery from chain: find_signer_pubkey() searches chain
   by fingerprint prefix. append_key_recovery() creates a recovery
   record signed by new key with old fingerprint + cosigner list.
   verify_chain() accepts recovery records.

6. Batch verification: /verify/batch web endpoint accepts multiple
   files, returns per-file status (verified/unverified/error) with
   exact vs perceptual match breakdown.

7. Chain position proof in receipt: verification receipts (now
   schema v3) include chain_proof with chain_id, chain_index,
   prev_hash, and record_hash for court admissibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 20:26:03 -04:00
Aaron D. Lee
792254699c Fix audit log surviving killswitch activation
The audit.jsonl file (containing usernames, actions, timestamps) was
not included in the PurgeScope.ALL destruction steps. An adversary
with filesystem access after a failed or partial purge could recover
operational evidence. Added destroy_audit_log step after temp files,
before config deletion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:45:14 -04:00
Aaron D. Lee
0d8c94bf82 Fix 6 security issues from post-FR audit
- Fix 3 missing CSRF tokens on admin user delete/reset and account
  key delete forms (were broken — CSRFProtect rejected submissions)
- Fix trust store path traversal: untrust_key() now validates
  fingerprint format ([0-9a-f]{32}) and checks resolved path
- Fix chain key rotation: old key is now revoked after rotation
  record, preventing compromised old keys from appending records
- Fix SSRF in deadman webhook: block private/internal IP targets
- Fix logout CSRF: /logout is now POST-only with CSRF token,
  preventing cross-site forced logout via img tags

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:44:15 -04:00
Aaron D. Lee
fb0cc3e39d Implement 14 power-user feature requests for field deployment
Critical:
- FR-01: Chain verification now supports key rotation via signed rotation
  records (soosef/key-rotation-v1 content type). Old single-signer
  invariant replaced with authorized-signers set.
- FR-02: Carrier images stripped of EXIF metadata by default before
  steganographic encoding (strip_metadata=True). Prevents source
  location/device leakage.

High priority:
- FR-03: Session timeout (default 15min) + secure cookie flags
  (HttpOnly, SameSite=Strict, Secure when HTTPS)
- FR-04: CSRF protection via Flask-WTF on all POST forms. Killswitch
  now requires password re-authentication.
- FR-05: Collaborator trust store — trust_key(), get_trusted_keys(),
  resolve_attestor_name(), untrust_key() in KeystoreManager.
- FR-06: Production WSGI server (Waitress) by default, Flask dev
  server only with --debug flag.
- FR-07: Dead man's switch sends warning during grace period via
  local file + optional webhook before auto-purge.

Medium:
- FR-08: Geofence get_current_location() via gpsd for --here support.
- FR-09: Batch attestation endpoint (/attest/batch) with SHA-256
  dedup and per-file status reporting.
- FR-10: Key backup tracking with last_backup_info() and
  is_backup_overdue() + backup_reminder_days config.
- FR-11: Verification receipts signed with instance Ed25519 key
  (schema_version bumped to 2).
- FR-12: Login rate limiting with configurable lockout (5 attempts,
  15 min default).

Nice-to-have:
- FR-13: Unified `soosef status` pre-flight command showing identity,
  channel key, deadman, geofence, chain, and backup status.
- FR-14: `soosef chain export` produces ZIP with JSON manifest,
  public key, and raw chain.bin for legal discovery.

Tests: 157 passed, 1 skipped, 1 pre-existing flaky test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:35:36 -04:00
Aaron D. Lee
384d7e89d9 Fix all mypy type errors (10 errors in 5 files)
Some checks failed
CI / lint (push) Successful in 22s
CI / typecheck (push) Successful in 21s
CI / test (push) Failing after 21s
- Use type: ignore for cbor2/json Any returns in serialization/deadman
- Fix callable→Callable in killswitch.py and usb_monitor.py
- Add Ed25519PrivateKey assertion in CLI chain-wrap path
- Allow None for RotationResult fingerprints
- Annotate channel key as str in manager.py

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:33:56 -04:00
Aaron D. Lee
17147856d1 Fix all 98 ruff lint errors across codebase
Some checks failed
CI / lint (push) Successful in 46s
CI / typecheck (push) Failing after 22s
CI / test (push) Failing after 20s
- Remove unused imports (app.py, stego_routes.py, killswitch.py, etc.)
- Sort import blocks (I001)
- Add missing os import in stego_routes.py (F821)
- Rename shadowed Click commands to avoid F811 (status→chain_status, show→chain_show)
- Rename uppercase locals R→earth_r, _HAS_QRCODE_READ→_has_qrcode_read (N806)
- Suppress false-positive F821 for get_username (closure scope)
- Use datetime.UTC alias (UP017)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:30:01 -04:00
Aaron D. Lee
5c74a5f4aa Fix black formatting and target Python 3.12 in CI
Some checks failed
CI / lint (push) Failing after 36s
CI / typecheck (push) Failing after 37s
CI / test (push) Failing after 24s
Reformat 8 files and add --target-version py312 to avoid
3.13 AST parsing issues with Python 3.12 container.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:26:32 -04:00
Aaron D. Lee
51c9b0a99a Fix 14 bugs and add features from power-user security audit
Critical fixes:
- Fix admin_delete_user missing current_user_id argument (TypeError on every delete)
- Fix self-signed cert OOM: bytes(2130706433) → IPv4Address("127.0.0.1")
- Add @login_required to attestation routes (attest, log); verify stays public
- Add auth guards to fieldkit (@admin_required on killswitch) and keys blueprints
- Fix cleanup_temp_files NameError in generate() route

Security hardening:
- Unify temp storage to ~/.soosef/temp/ so killswitch purge covers web uploads
- Replace Path.unlink() with secure deletion (shred fallback) in temp_storage
- Add structured audit log (audit.jsonl) for admin, key, and killswitch actions

New features:
- Dead man's switch background enforcement thread in serve + check-deadman CLI
- Key rotation: soosef keys rotate-identity/rotate-channel with archiving
- Batch attestation: soosef attest batch <dir> with progress and error handling
- Geofence CLI: set/check/clear commands with config persistence
- USB CLI: snapshot/check commands against device whitelist
- Verification receipt download (/verify/receipt JSON endpoint + UI button)
- IdentityInfo.created_at populated from sidecar meta.json (mtime fallback)

Data layer:
- ChainStore.get() now O(1) via byte-offset index built during state rebuild
- Add federation module (chain, models, serialization, entropy)

Includes 45+ new tests across chain, deadman, key rotation, killswitch, and
serialization modules.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 17:06:33 -04:00
Aaron D. Lee
b8d4eb5933 Add core modules, web frontend, CLI, keystore, and fieldkit
Core:
- paths.py: centralized ~/.soosef/ path constants
- config.py: JSON config loader with dataclass defaults
- exceptions.py: SoosefError hierarchy
- cli.py: unified Click CLI wrapping stegasoo + verisoo + native commands

Keystore:
- manager.py: unified key management (Ed25519 identity + channel keys)
- models.py: IdentityInfo, KeystoreStatus dataclasses
- export.py: encrypted key bundle export/import for USB transfer

Fieldkit:
- killswitch.py: ordered emergency data destruction (keys first)
- deadman.py: dead man's switch with check-in timer
- tamper.py: SHA-256 file integrity baseline + checking
- usb_monitor.py: pyudev USB whitelist enforcement
- geofence.py: haversine-based GPS boundary checking

Web frontend (Flask app factory + blueprints):
- app.py: create_app() factory with context processor
- blueprints: stego, attest, fieldkit, keys, admin
- templates: base.html (dark theme, unified nav), dashboard, all section pages
- static: CSS, favicon

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:30:13 -04:00