Complete project rebrand for better positioning in the press freedom and digital security space. FieldWitness communicates both field deployment and evidence testimony — appropriate for the target audience of journalists, NGOs, and human rights organizations. Rename mapping: - soosef → fieldwitness (package, CLI, all imports) - soosef.stegasoo → fieldwitness.stego - soosef.verisoo → fieldwitness.attest - ~/.soosef/ → ~/.fwmetadata/ (innocuous data dir name) - SOOSEF_DATA_DIR → FIELDWITNESS_DATA_DIR - SoosefConfig → FieldWitnessConfig - SoosefError → FieldWitnessError Also includes: - License switch from MIT to GPL-3.0 - C2PA bridge module (Phase 0-2 MVP): cert.py, export.py, vendor_assertions.py - README repositioned to lead with provenance/federation, stego backgrounded - Threat model skeleton at docs/security/threat-model.md - Planning docs: docs/planning/c2pa-integration.md, docs/planning/gtm-feasibility.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
16 KiB
FieldWitness Admin Operations Guide
Audience: IT administrators, system operators, and technically competent journalists responsible for deploying, configuring, and maintaining FieldWitness instances for their organization.
Prerequisites: Familiarity with Linux command line, Docker basics, and SSH. For Tier 1
USB builds, familiarity with Debian live-build.
Overview
This guide covers the operational tasks an admin performs after initial deployment. For installation and deployment, see deployment.md. For architecture details, see docs/architecture/.
Your responsibilities as a FieldWitness admin:
- Deploy and maintain FieldWitness instances (Tier 1 USB, Tier 2 server, Tier 3 relay)
- Manage user accounts and access
- Configure threat level presets for your environment
- Manage the source drop box
- Set up and maintain federation between organizations
- Monitor system health and perform backups
- Respond to security incidents
1. User Management
Creating User Accounts
On first start, the web UI prompts for the first admin account. Additional users are
created through the Admin panel at /admin/.
Each user has:
- A username and password (stored as Argon2id hashes in SQLite)
- An admin flag (admin users can manage other accounts and the drop box)
Password Resets
From the admin panel, issue a temporary password for a locked-out user. The user should
change it on next login. All password resets are recorded in the audit log
(~/.fwmetadata/audit.jsonl).
Account Lockout
After login_lockout_attempts (default: 5) failed logins, the account is locked for
login_lockout_minutes (default: 15). Lockout state is in-memory and clears on server
restart.
For persistent lockout (e.g., a compromised account), delete the user from the admin panel.
Audit Trail
All admin actions are logged to ~/.fwmetadata/audit.jsonl in JSON-lines format:
{"timestamp": "2026-04-01T12:00:00+00:00", "actor": "admin", "action": "user.create", "target": "user:reporter1", "outcome": "success", "source": "web"}
Actions logged: user.create, user.delete, user.password_reset,
key.channel.generate, key.identity.generate, killswitch.fire
Warning
: The audit log is destroyed by the killswitch. This is intentional -- in a field compromise, data destruction takes precedence over audit preservation.
2. Threat Level Configuration
FieldWitness ships four presets at deploy/config-presets/. Select based on your operational
environment.
Applying a Preset
$ cp deploy/config-presets/high-threat.json ~/.fwmetadata/config.json
Restart the server to apply.
Preset Summary
| Preset | Session Timeout | Killswitch | Dead Man's Switch | USB Monitor | Cover Name |
|---|---|---|---|---|---|
| Low (press freedom) | 30 min | Off | Off | Off | None |
| Medium (restricted press) | 15 min | On | 48h / 4h grace | On | "Office Document Manager" |
| High (conflict zone) | 5 min | On | 12h / 1h grace | On | "Local Inventory Tracker" |
| Critical (targeted surveillance) | 3 min | On | 6h / 1h grace | On | "System Statistics" |
Custom Configuration
Edit ~/.fwmetadata/config.json directly. All fields have defaults. Key fields for security:
| Field | What It Controls |
|---|---|
host |
Bind address. 127.0.0.1 = local only; 0.0.0.0 = LAN access |
session_timeout_minutes |
How long before idle sessions expire |
killswitch_enabled |
Whether the software killswitch is available |
deadman_enabled |
Whether the dead man's switch is active |
deadman_interval_hours |
Hours between required check-ins |
deadman_grace_hours |
Grace period after missed check-in before auto-purge |
deadman_warning_webhook |
URL to POST a JSON warning during grace period |
cover_name |
CN for the self-signed TLS certificate (cover/duress mode) |
backup_reminder_days |
Days before fieldwitness status warns about overdue backups |
Warning
: Setting
auth_enabled: falsedisables all login requirements. Never do this on a network-accessible instance.
3. Source Drop Box Operations
The drop box provides SecureDrop-style anonymous file intake.
Creating Upload Tokens
- Go to
/dropbox/adminin the web UI (admin account required) - Set a label (internal only -- the source never sees this)
- Set expiry in hours (default: 24)
- Set max files (default: 10)
- Click Create Token
You receive a URL like https://<host>:<port>/dropbox/upload/<token>.
Sharing URLs With Sources
Share the URL over an already-secure channel only:
- Best: Hand-written on paper, in person
- Good: Signal, Wire, or other end-to-end encrypted messenger
- Acceptable: Encrypted email (PGP/GPG)
- Never: Unencrypted email, SMS, or any channel you do not control
What Happens When a Source Uploads
- The source opens the URL in any browser (no account needed, no FieldWitness branding)
- Their browser computes SHA-256 hashes client-side before upload (SubtleCrypto)
- Files are uploaded and processed:
- EXIF metadata is extracted (evidentiary fields: GPS, timestamp)
- All metadata is stripped from the stored copy (protects source device info)
- The original bytes are attested (signed) before stripping
- The source receives a receipt code (HMAC of file hash + token)
- Files are stored in
~/.fwmetadata/temp/dropbox/with mode 0700
Revoking Tokens
From /dropbox/admin, click Revoke on any active token. The token is immediately
deleted from the database. Any source with the URL can no longer upload.
Receipt Verification
Sources can verify their submission was received at /dropbox/verify-receipt by entering
their receipt code. This returns the filename, SHA-256, and reception timestamp.
Operational Security
- The upload page has no FieldWitness branding -- it is a minimal HTML form
- No external resources are loaded (no CDN, fonts, analytics) -- Tor Browser compatible
- FieldWitness does not log source IP addresses
- If using a reverse proxy (nginx, Caddy), disable access logging for
/dropbox/upload/ - Tokens auto-expire and are cleaned up on every admin page load
- For maximum source protection, run FieldWitness as a Tor hidden service
Storage Management
Uploaded files accumulate in ~/.fwmetadata/temp/dropbox/. Periodically review and process
submissions, then remove them from the temp directory. The files are not automatically
cleaned up (they persist until you act on them or the killswitch fires).
4. Key Management
Two Key Domains
FieldWitness manages two independent key types:
| Key | Algorithm | Location | Purpose |
|---|---|---|---|
| Identity key | Ed25519 | ~/.fwmetadata/identity/ |
Sign attestations, chain records |
| Channel key | AES-256-GCM (Argon2id-derived) | ~/.fwmetadata/stego/channel.key |
Steganographic encoding |
These are never merged. Rotating one does not affect the other.
Key Rotation
Identity rotation archives the old keypair and generates a new one. If the chain is
enabled, a fieldwitness/key-rotation-v1 record is signed by the OLD key, creating a
verifiable trust chain.
$ fieldwitness keys rotate-identity
After rotating, immediately:
- Take a fresh backup (
fieldwitness keys export) - Notify all collaborators of the new fingerprint
- Update trusted-key lists at partner organizations
Channel rotation archives the old key and generates a new one:
$ fieldwitness keys rotate-channel
After rotating, share the new channel key with all stego correspondents.
Trust Store
Import collaborator public keys so you can verify their attestations and accept their federation bundles:
$ fieldwitness keys trust --import /media/usb/partner-pubkey.pem
Always verify fingerprints out-of-band (in person or over a known-secure voice channel).
List trusted keys:
$ fieldwitness keys show
Remove a trusted key:
$ fieldwitness keys untrust <fingerprint>
Backup Schedule
FieldWitness warns when backups are overdue (configurable via backup_reminder_days).
# Create encrypted backup
$ fieldwitness keys export -o /media/usb/backup.enc
# Check backup status
$ fieldwitness status
Store backups on separate physical media, in a different location from the device.
5. Federation Setup
Federation allows multiple FieldWitness instances to exchange attestation records.
Adding Federation Peers
Through the web UI: Go to /federation/, click Add Peer, enter the peer's URL
and Ed25519 fingerprint.
Through the CLI or peer_store:
# Peers are managed via the web UI or programmatically through PeerStore
Trust Key Exchange
Before two organizations can federate, exchange public keys:
- Export your public key:
cp ~/.fwmetadata/identity/public.pem /media/usb/our-pubkey.pem - Give it to the partner organization (physical handoff or secure channel)
- Import their key:
fieldwitness keys trust --import /media/usb/their-pubkey.pem - Verify fingerprints out-of-band
Exporting Attestation Bundles
# Export all records
$ fieldwitness chain export --output /media/usb/bundle.zip
# Export a specific range
$ fieldwitness chain export --start 100 --end 200 --output /media/usb/bundle.zip
# Export filtered by investigation
# (investigation tag is set during attestation)
Importing Attestation Bundles
On the receiving instance, imported records are:
- Verified against the trust store (untrusted signers are rejected)
- Deduplicated by SHA-256 (existing records are skipped)
- Tagged with
federated_frommetadata - Acknowledged via a delivery-ack chain record (two-way handshake)
Gossip Sync (Tier 2 <-> Tier 3)
If the Tier 2 server and Tier 3 relay have network connectivity, gossip sync runs
automatically at the configured interval (default: 60 seconds, set via
FIELDWITNESS_GOSSIP_INTERVAL environment variable).
Gossip flow:
- Nodes exchange Merkle roots
- If roots differ, request consistency proof
- Fetch missing records
- Append to local log
Monitor sync status at /federation/ in the web UI.
Airgapped Federation
All federation is designed for sneakernet operation:
- Export bundle to USB on sending instance
- Physically carry USB to receiving instance
- Import bundle
- Optionally export delivery acknowledgment back on USB
No network connectivity is required at any point.
6. Chain and Anchoring
Chain Verification
Verify the full chain periodically:
$ fieldwitness chain verify
This checks all hash linkage and Ed25519 signatures. It also verifies key rotation records and tracks authorized signers.
Timestamp Anchoring
Anchor the chain head to prove it existed before a given time:
# Automated (requires network)
$ fieldwitness chain anchor --tsa https://freetsa.org/tsr
# Manual (prints hash for external submission)
$ fieldwitness chain anchor
A single anchor implicitly timestamps every prior record (the chain is append-only).
When to anchor:
- Before sharing evidence with third parties
- At regular intervals (daily or weekly)
- Before key rotation
- Before and after major investigations
Selective Disclosure
For legal discovery or court orders, produce a proof showing specific records while keeping others redacted:
$ fieldwitness chain disclose -i 42,43,44 -o disclosure.json
The output includes full records for selected indices and hash-only entries for everything else. A third party can verify the selected records are part of an unbroken chain.
7. Evidence Preservation
Evidence Packages
For handing evidence to lawyers, courts, or organizations without FieldWitness:
Self-contained ZIP containing original images, attestation records, chain data, your
public key, a standalone verify.py, and a README. The recipient verifies with:
$ pip install cryptography
$ python verify.py
Cold Archives
For long-term preservation (10+ year horizon), OAIS-aligned:
Full state export including chain binary, attestation log, LMDB index, anchors, public
key, trusted keys, optional encrypted key bundle, ALGORITHMS.txt, and verify.py.
When to create cold archives:
- Weekly or monthly as part of backup strategy
- Before key rotation or travel
- When archiving a completed investigation
Store on at least two separate physical media in different locations.
8. Monitoring and Health
Health Endpoint
# Web UI
$ curl -k https://127.0.0.1:5000/health
# Federation API
$ curl http://localhost:8000/health
Returns capabilities (stego-lsb, stego-dct, attest, fieldkit, chain).
System Status
$ fieldwitness status --json
Checks: identity key, channel key, chain integrity, dead man's switch state, backup status, geofence, trusted keys.
Docker Monitoring
# Service status
$ docker compose ps
# Logs
$ docker compose logs -f server
# Resource usage
$ docker stats
The Docker images include HEALTHCHECK directives that poll /health every 30 seconds.
9. Incident Response
Device Seizure (Imminent)
- Trigger killswitch:
fieldwitness fieldkit purge --confirm CONFIRM-PURGE - For Tier 1 USB: pull the USB stick and destroy it physically if possible
- Verify with a separate device that federation copies are intact
Device Seizure (After the Fact)
- Assume all local data is compromised
- Verify Tier 2/3 copies of attestation data
- Generate new keys on a fresh instance
- Record a key recovery event in the chain (if the old chain is still accessible)
- Notify all collaborators to update their trust stores
Federation Peer Compromise
- The compromised peer has attestation metadata (hashes, signatures, timestamps) but not decrypted content
- Remove the peer from your peer list (
/federation/> Remove Peer) - Assess what metadata exposure means for your organization
- Consider whether attestation patterns reveal sensitive information
Dead Man's Switch Triggered Accidentally
Data is gone. Restore from the most recent backup:
$ fieldwitness init
$ fieldwitness keys import -b /media/usb/backup.enc
Federation copies of attestation data are unaffected. Local attestations created since the last federation sync or backup are lost.
10. Maintenance Tasks
Regular Schedule
| Task | Frequency | Command |
|---|---|---|
| Check system status | Daily | fieldwitness status |
| Check in (if deadman armed) | Per interval | fieldwitness fieldkit checkin |
| Backup keys | Per backup_reminder_days |
fieldwitness keys export |
| Verify chain integrity | Weekly | fieldwitness chain verify |
| Anchor chain | Weekly | fieldwitness chain anchor |
| Review drop box submissions | As needed | /dropbox/admin |
| Clean temp files | Monthly | Remove processed files from ~/.fwmetadata/temp/ |
| Create cold archive | Monthly | Export via CLI or web |
| Update FieldWitness | As releases are available | pip install --upgrade fieldwitness |
Docker Volume Backup
$ docker compose stop server
$ docker run --rm -v server-data:/data -v /backup:/backup \
busybox tar czf /backup/fieldwitness-$(date +%Y%m%d).tar.gz -C /data .
$ docker compose start server
Log Rotation
audit.jsonl grows indefinitely. On long-running Tier 2 servers, archive old entries
periodically. The audit log is append-only; truncate by copying the tail:
$ tail -n 10000 ~/.fwmetadata/audit.jsonl > ~/.fwmetadata/audit.jsonl.tmp
$ mv ~/.fwmetadata/audit.jsonl.tmp ~/.fwmetadata/audit.jsonl
Warning
: Truncating the audit log removes historical records. Archive the full file before truncating if you need the history for compliance or legal purposes.