EPSILOCK runs as three demo apps:
main-node/: admin panel + HTTPS/WSS server (/ws)user-node/: user chat node dashboards that connect to main node over WSSattacker-node/: separate educational dashboard that only receives intentionally mirrored encrypted packet copies
Important: this is an educational simulation for hackathon demos. It does not build real sniffing/MITM tooling and does not claim to be unhackable.
- HTTPS/WSS transport (TLS cert paths from env)
- JWT auth with token version checks
- bcrypt password hashing
- AES-256-GCM demo packet encryption (
DEMO_SHARED_KEY) - No persistent chat plaintext storage
- No plaintext cover payload storage
- Only metadata (
PacketMeta,NodeSession,Incident) is persisted
- Main node can mirror encrypted packet metadata + crypto envelope to attacker-node.
- Attacker-node can optionally attempt demo decryption if
DEMO_SHARED_KEYis configured ("Demo leaked key mode"). - Decrypted previews are in-memory UI only on attacker-node and are never persisted.
Cover traffic wording used in UI:
- "Cover traffic reduces metadata leakage and timing-analysis confidence."
- It does not make the system unhackable.
Generate local dev certs:
npm run certs- Copy env:
cp .env.example .env- Install dependencies:
npm install- Generate certs:
npm run certs- Seed admin account:
npm run seed:adminDefault admin:
- username:
admin - password:
admin123
Terminal 1:
npm run dev:mainTerminal 2:
npm run dev:node1Terminal 3:
npm run dev:node2Terminal 4:
npm run dev:attackerDefault URLs:
- Main admin:
https://localhost:8443 - User node 1:
https://localhost:3001 - User node 2:
https://localhost:3002 - Attacker node:
https://localhost:4001/attacker
/admin/admin/users/admin/rooms/admin/nodes/admin/incidents/admin/attacker-demo/admin/security-settings
Open /admin/security-settings.
You can configure:
ATTACKER_DEMO_ENABLEDCOVER_TRAFFIC_ENABLEDCOVER_TRAFFIC_INTERVAL_MSCOVER_TRAFFIC_JITTER_MSCOVER_TRAFFIC_RATIO
When saved:
- Main node broadcasts
SECURITY_SETTINGS_UPDATEDto admin sockets - Main node broadcasts
COVER_TRAFFIC_CONFIG_UPDATEDto connected user nodes - Main node broadcasts
ATTACKER_DEMO_SETTINGS_UPDATEDto attacker-node - User nodes start/stop/reconfigure cover packets immediately
- Attacker dashboard updates instantly
Main /ws supports:
- admin socket (
client=admin, JWT) - user node sockets (JWT +
nodeId+userId) - attacker demo socket (
client=attacker,ATTACKER_DEMO_TOKEN)
Attacker socket is accepted only when:
NODE_ENV !== productionOR attacker demo is enabled- token matches
ATTACKER_DEMO_TOKEN - origin passes allowed origin rules
- Start all 4 processes (main, node1, node2, attacker).
- In admin, create users and a room; add both users to room.
- Log in from both user nodes, select room, join room, send message.
- Open attacker dashboard and observe packets with cover traffic OFF.
- In
/admin/security-settings, turn cover traffic ON. - Send similar messages again.
- Observe attacker dashboard now receives mixed real + cover packets and confidence drops to LOW/MEDIUM.
- Explain: encryption protects content; cover traffic adds noise to reduce metadata/timing-analysis confidence.
Chat controls are enabled only when all are true:
- WSS connected
- Node authenticated (
NODE_AUTH_OK) - Room joined (
ROOM_JOIN_OK)
Manual checks:
- Open user chat page: message/file controls stay disabled.
- Before WSS is connected: controls disabled.
- After WSS open but before node auth: controls disabled.
- After
NODE_AUTH_OKbut before join: controls disabled, room join available. - Select room but do not join: controls disabled.
- Click join room: controls remain disabled while waiting.
- After
ROOM_JOIN_OK: controls enabled. - Try invalid/fake room send: server returns
SEND_DENIED, no broadcast. - Disconnect WSS: controls disable immediately.
- Freeze room in admin: sends are denied and user sees denied reason.
- Start main node.
- Start user node 1 and user node 2.
- Login as two different users.
- Join the same room from both dashboards.
- Send a message from user 1.
- Expected: user 2 sees the message bubble in chat log.
- Expected: user 1 sees own message exactly once (server echo).
- Turn cover traffic ON from admin settings.
- Expected: cover packets appear in attacker demo, not in user chat UI.
- Join different rooms.
- Expected: messages do not cross rooms.
- Freeze room in admin.
- Expected: send denied (or input disabled) and no new messages rendered.
-
Message flood: send more than 8 messages in 10 seconds. Expected:
MESSAGE_FLOODincident, socket disconnected, admin alert/beep. -
WS event burst: spam 25+ WS events in 5 seconds. Expected:
WS_EVENT_BURSTincident and socket disconnect. -
Invalid room join: repeatedly join an unassigned room. Expected:
ROOM_JOIN_DENIED; repeated attempts triggerINVALID_ROOM_JOINand block/reset enforcement. -
Invalid room send: send packet with different
roomIdthan joined room. Expected:INVALID_ROOM_SENDincident and security action. -
Oversized payload: send payload above policy threshold. Expected:
OVERSIZED_PAYLOADincident and high-severity enforcement. -
File abuse: send unsupported mime type or exceed file rate. Expected:
FILE_ABUSEincident. -
Repeated failed login: fail login 5+ times. Expected:
REPEATED_AUTH_FAILURESincident and account block/reset requirement. -
Abnormal disconnect: connect/disconnect repeatedly. Expected:
ABNORMAL_DISCONNECTincident. -
Origin validation failure: connect from unapproved origin. Expected: upgrade rejected and
ORIGIN_VALIDATION_FAILEDincident. -
Token/session mismatch: reconnect with stale token after tokenVersion increment. Expected:
TOKEN_SESSION_MISMATCHincident and forced logout. -
Admin disconnect: use “Disconnect User Now”. Expected: all active sockets receive
FORCE_LOGOUT. -
Multi-device anomaly logout: same user logged in on node1 + node2, trigger high/critical anomaly. Expected: both devices logout immediately.
-
Admin reset-password unlock: Expected: user unblocked,
requirePasswordReset=false, old sessions revoked, login only with new password.
MAIN_NODE_PORT=8443USER_NODE_1_PORT=3001USER_NODE_2_PORT=3002ATTACKER_NODE_PORT=4001MAIN_NODE_WSS_URL=wss://localhost:8443/wsATTACKER_NODE_URL=https://localhost:4001/attackerATTACKER_DEMO_ENABLED=trueATTACKER_DEMO_TOKEN=change-this-demo-tokenDEMO_SHARED_KEY=<hex-64 or passphrase>
npm run dev:mainnpm run dev:node1npm run dev:node2npm run dev:attackernpm run certsnpm run seed:admin