Security Audit

Scope

Consolidated security findings from analysis of all FaceKom services: vuer_oss, vuer_css, vuer_cv, esign, pdfservice, and nyilvantarto-scraper. Findings organized by severity.

Summary

SeverityCount
CRITICAL2
HIGH6
MEDIUM5
LOW6
Positive12+

CRITICAL

1. pickle.loads() RCE in vuer_cv AppCache

CRITICAL: Remote Code Execution

File: vuer_cv/server/appcache.py:106

return pickle.loads(raw)

If an attacker can write to Redis, they can achieve arbitrary code execution via crafted pickle payloads. Metadata keys are predictable (metadata:{imageId}:{metaName}).

Impact: Full server compromise Prerequisite: Write access to Redis (no auth visible in code) Recommendation: Replace pickle.loads() with json.loads() or use pickle.loads() with a restricted unpickler

2. Command Injection in Janus exec()

CRITICAL: Command Injection

Files:

  • vuer_oss/server/convert/JanusConvertProcess.js:52
  • vuer_oss/server/convert/JanusMetaProcess.js:35

Both use exec() with template literal string interpolation:

exec(`janus-pp-rec ${this.flags} ${this.inputFile} ${this.outputFile}`, this.options)

If flags, inputFile, or outputFile contain shell metacharacters (;, |, `, $()), this enables command injection. Inputs likely come from media file paths (system-generated), but a crafted filename could exploit this.

Impact: Arbitrary command execution on server Recommendation: Replace exec() with execFile('janus-pp-rec', [flags, inputFile, outputFile])


HIGH

3. Missing Auth on Data Import Endpoints

HIGH: Missing Authorization

Files:

  • vuer_oss/server/web/routes/importDataRecords.endpoint.js:43 — TODO: “handle access roles”
  • vuer_oss/server/web/routes/importDataRoom.endpoint.js:85 — TODO: “check accessibility”

Data import endpoints may lack proper authorization checks. This is a significant concern for an enterprise KYC platform.

4. innerHTML XSS in vuer_css

HIGH: Cross-Site Scripting

Multiple innerHTML assignments with potentially untrusted data:

FileLineVector
VideoFeed.js337this.videoMessageContent.innerHTML = content
VideoFeed.js374/378innerHTML with holdMedia URL from socket event
modal.js168/187this.body.innerHTML = content / this.bodyText.innerHTML = text
Form.js87/222text.innerHTML = this.formDictionary.t(textKey)
waiting-room.script.js37/43Video/image source injection
RequestCallback.js99text.innerHTML = dict.t(errorText)

The VideoFeed.js case is most concerning: holdMedia comes from a socket event (videochat:remoteUserHoldMedia) and is inserted as an <img src>.

5. CSRF Commented Out on /api/submit-appointment

HIGH: CSRF Bypass

File: vuer_css/server/web/routes.js:254

CSRF protection is commented out on the submit-appointment route, leaving it vulnerable to cross-site request forgery.

6. CSP Disabled on Document Paths

HIGH: Content Security Policy Bypass

File: vuer_oss/server/web/WebServer.js

Multiple paths disable CSP entirely: /api/document/, /import-data/. This removes XSS protections on these endpoints.

7. Hardcoded Dev Credentials

HIGH: Hardcoded Secrets in Config

File: esign_oss/config/dev.json contains:

ItemRisk
Firebase RSA private keyCould be real production key
SMS API token (PNBOsgikXKqmJ7sMMOdWXUSdRfE5J2RHeg5OaiSP)Could be real
JWT secret, session secret, JWE keystoreDev only
Crypto key, seal passwordDev only
Mailtrap SMTP credentialsTest service
TSA test credentialsTest only
DB credentials (dev/dev)Dev only

Mitigating factor: These are in dev config, not production. But the Firebase key and SMS token could be real.

8. NODE_TLS_REJECT_UNAUTHORIZED=0

HIGH: TLS Bypass

Files: vuer_oss/server/bootstrap/process-settings.js, esign_css, esign_oss

When config.settings.allowSelfSignedCerts is true, ALL TLS certificate validation is disabled globally. The dev config enables this. If accidentally left on in production, MITM attacks become trivial.


MEDIUM

9. Token Logging in JwtKioskAuth

MEDIUM: Token Leakage

File: vuer_oss/server/queue/rpc_server/JwtKioskAuth.js:20

logger.warn(`JWT Token authentication failed for token: '${jwtToken}'`, err)

Logs the raw encrypted JWT token on auth failure. Could aid an attacker with log access.

Recommendation: Log token hash or first/last characters only.

10. CORS Mutation Race Condition

MEDIUM: CORS Configuration Race

File: vuer_css/server/web/routes.js:203-215

WebSDK CORS handler mutates shared corsOptions.origin object based on Referer header. Under concurrent requests, one request’s CORS origin could leak to another.

11. Session Scanning DoS Vector

MEDIUM: Denial of Service

File: vuer_oss/server/web/session.js:4-17

listSessions() loads ALL sessions into memory and parses JSON to find a user’s sessions. O(n) scan with no index. Could be a DoS vector if many sessions exist.

12. Weak PBKDF2 (5000 iterations)

MEDIUM: Weak Key Derivation

File: vuer_oss/server/gcm.js and esign_oss/server/gcm.js

AES-256-GCM key derivation uses only 5000 PBKDF2 iterations. Modern recommendations (OWASP) suggest 600,000+ for SHA-256.

13. Unencrypted Redis

MEDIUM: Unencrypted Data Store

All vuer_cv image data, metadata, and RPC communication goes through Redis with no visible encryption or authentication in code (depends on config). Redis as single point of failure.


LOW

14. Empty Catch Blocks

LOW: Silent Error Swallowing

  • vuer_oss/server/service/MediaFileService.js:173catch (_) {}
  • vuer_oss/server/web/session.js:13catch (e) {}

Could mask failures indicating security issues.

15. Deprecated csurf Package

LOW: Deprecated Dependency

Both vuer_css and esign use the csurf package which is deprecated and has known issues.

16. CSP Bypassed for IE/Safari

LOW: CSP Bypass

File: vuer_css/server/web/WebServer.js:162

CSP middleware completely skipped for Internet Explorer and Safari browsers.

17. Password Over RabbitMQ

LOW: Plaintext Credentials in Transit

Customer passwords travel in plaintext over RabbitMQ RPC (esign_css esign_oss). The RabbitMQ connection is TLS-encrypted (AMQPS), which mitigates this.

18. Hardcoded Test Password

LOW: Hardcoded Credential

File: vuer_oss/server.js:290-292

In test mode, PasswordService.generateTemporaryPassword() returns the hardcoded string 'temppassword' for all temporary passwords. If test mode is accidentally enabled in production, all temp passwords become guessable.

19. Config.get() Falsy Bug

LOW: Logic Bug

config.get() in both vuer_css and esign treats 0 and '' as missing values due to !current[path[0]] check. Could cause unexpected behavior with valid falsy config values.


Positive Security Findings

Security Strengths

The codebase demonstrates many strong security practices:

PracticeDetails
No eval()No eval(), Function(), or dynamic code execution in Node.js code
No raw SQLConsistent Sequelize ORM usage; no SQL injection vectors found
Helmet.jsComprehensive HTTP security headers on all Express apps
CSRF protectioncsurf middleware with secure, httpOnly, sameSite=strict cookies
Rate limitingRateLimiterService with configurable throttle, cooldown, and attempt limits
Multi-factor authTOTP + WebAuthn/FIDO2 support
JWE encryptionJWT tokens encrypted before transmission
Encryption at restPer-domain crypto services for media, certs, attachments, data
Audit logging50+ event types logged to AuditLog table
Trusted timestampsRFC 3161 timestamping for legal compliance
Session-level ACLFine-grained access control beyond role-based
Host header validationBlocks requests with unexpected Host headers
Config maskinggetSecureConfig() properly masks sensitive fields for logging
IP filteringConfigurable per-endpoint IP throttling
Evidence collectionnyilvantarto-scraper creates evidence ZIPs for legal compliance
Disaster modevuer_css can block new authentications during incidents

Service-Specific Notes

vuer_cv

  • No eval(), os.system(), or yaml.load() found
  • Only subprocess.run() with hardcoded commands (nvidia-smi, lscpu, supervisorctl)
  • No authentication on HTTP/WS endpoints (relies on Nginx proxy)
  • File path traversal in StreamPlayerCVTask mitigated by os.path.abspath()

vuer_oss

  • No hardcoded secrets in server code (all via config)
  • Express error handler properly categorizes error types
  • Sensitive config field masking for logging
  • 50+ audit event types tracked

esign

  • AES-256-GCM encryption for certificate passwords (good)
  • External webhooks can use HTTP Basic Auth (good)
  • Strict CSP with nonce-based script sources (good, but IE/Safari exception)