Threat Model v1.0

Meridian PMS
Security Assessment

Version 1.0
Date December 19, 2025
Author Security Architecture Team
Status Draft

Executive Summary

Meridian PMS is a cloud-hosted healthcare patient management system built on AWS infrastructure using a microservices architecture. The platform enables healthcare organizations to manage patient records, appointments, medications, and telehealth sessions through a publicly accessible web portal. Given its handling of Protected Health Information (PHI) and Personally Identifiable Information (PII), the system falls under HIPAA regulatory requirements and represents a high-value target for threat actors.

This threat model assesses the security posture of Meridian PMS's core components: Amazon Cognito authentication, JWT session management, MariaDB patient data storage, S3 file storage, real-time WebRTC/Socket.IO communications, and third-party API integrations. The analysis identifies 15 prioritized threats across authentication bypass, data exposure, API abuse, and infrastructure compromise categories.

Key Findings

The current architecture has significant gaps in JWT validation hardening, S3 access controls, WebRTC TURN server authentication, and audit logging completeness. Eight high-risk threats require immediate remediation to achieve acceptable HIPAA compliance posture. The third-party integration with ScriptGuard introduces supply chain risk that is not adequately addressed by current controls.

Architecture Diagram

flowchart TB subgraph Internet["Internet (Untrusted)"] User[Healthcare Staff] Patient[Patient Portal Users] ExtAPI[ScriptGuard API] end subgraph TrustBoundary1["DMZ - Public Facing"] WAF[AWS WAF] ALB[Application Load Balancer] end subgraph TrustBoundary2["Application Tier"] React[React Frontend
Apache/EC2] NodeAPI[Node.js API
Express.js] Lambda[AWS Lambda
Serverless Functions] WebRTC[WebRTC Gateway
Telehealth Video] SocketIO[Socket.IO Server
Real-time Messaging] end subgraph TrustBoundary3["Authentication"] Cognito[Amazon Cognito
User Pools + 2FA] JWT[JWT Token Service] end subgraph TrustBoundary4["Data Tier"] MariaDB[(MariaDB
Patient Records)] S3[(AWS S3
File Storage)] end subgraph TrustBoundary5["Monitoring"] Prometheus[Prometheus] ELK[ELK Stack] end User --> WAF Patient --> WAF WAF --> ALB ALB --> React React --> NodeAPI NodeAPI --> Cognito Cognito --> JWT NodeAPI --> MariaDB NodeAPI --> S3 NodeAPI --> Lambda NodeAPI --> WebRTC NodeAPI --> SocketIO NodeAPI --> ExtAPI NodeAPI --> Prometheus NodeAPI --> ELK Lambda --> MariaDB Lambda --> S3

Assets Inventory

Asset Description Classification Owner Location
Patient Records Name, DOB, SSN, address, medical history PHI/PII Critical Data Team MariaDB
Medical Documents Lab results, imaging, prescriptions PHI Critical Data Team S3
User Credentials Passwords, MFA secrets, session tokens Sensitive Security Team Cognito
Appointment Data Scheduling, provider assignments PHI High Application Team MariaDB
Medication Records Prescriptions, dosages, refill history PHI Critical Data Team MariaDB
Telehealth Sessions Video streams, chat transcripts PHI Critical Application Team WebRTC/S3
Audit Logs Access logs, authentication events Sensitive Security Team ELK Stack
API Keys Third-party integration credentials Sensitive DevOps Team AWS Secrets Manager
JWT Signing Keys Token signing/verification keys Critical Security Team Cognito/EC2

Risk Scoring Methodology

Risk ratings follow the OWASP Risk Rating Methodology: Risk = Likelihood x Impact.

Likelihood considers exploitability (skill required, tooling availability, public knowledge of the attack vector) and exposure (whether the component is internet-facing, requires authentication, or sits behind existing controls).

Impact considers the scope of data at risk (PHI record count, data sensitivity classification), HIPAA regulatory exposure (specific §164 subsections violated), and service availability consequences.

High Risk

Exploitable by an unauthenticated or low-skill attacker against an internet-facing component, OR directly exposes PHI/PII, OR bypasses a primary security control (authentication, authorization, encryption).

Medium Risk

Requires authenticated access or specific preconditions to exploit, AND exposes system metadata or operational data rather than PHI directly, OR degrades a defence-in-depth layer without fully bypassing it.

Threat Register

ID Category Threat Component Risk Status
AUTH-01 Spoofing JWT algorithm confusion—attacker substitutes RS256 with HS256 using public key as secret JWT Authentication High Not Addressed
AUTH-02 Spoofing Cognito user enumeration via differential response timing on login attempts Amazon Cognito Medium Not Addressed
AUTH-03 Elevation of Privilege JWT token theft via XSS allows session hijacking with full user privileges Frontend/JWT High Partial
AUTH-04 Repudiation Insufficient logging of authentication failures prevents breach detection ELK Stack Medium Not Addressed
DATA-01 Info Disclosure S3 bucket misconfiguration exposes patient documents publicly S3 Storage High Not Addressed
DATA-02 Info Disclosure MariaDB connection strings hardcoded in application code or environment variables Node.js API High Not Addressed
DATA-03 Tampering SQL injection in patient search endpoint modifies or extracts PHI MariaDB/API High Not Addressed
API-01 Elevation of Privilege IDOR vulnerability allows patients to access other patients' records via predictable IDs Patient API High Not Addressed
API-02 DoS Lack of rate limiting enables API abuse and resource exhaustion Node.js API Medium Not Addressed
API-03 Spoofing ScriptGuard API key compromise enables unauthorized medication data access Third-party Integration High Not Addressed
RTC-01 Info Disclosure WebRTC TURN server lacks authentication, allowing unauthorized relay usage WebRTC Gateway High Not Addressed
RTC-02 Info Disclosure Socket.IO connections lack origin validation, enabling cross-site hijacking Socket.IO Server Medium Not Addressed
INFRA-01 Elevation of Privilege Lambda function IAM roles overly permissive, enabling lateral movement AWS Lambda Medium Not Addressed
INFRA-02 Info Disclosure Prometheus metrics endpoint exposed without authentication leaks system info Prometheus Medium Not Addressed
INFRA-03 Tampering GitHub Actions workflow injection via malicious PR modifies deployment CI/CD Pipeline High Not Addressed

Mitigations

AUTH-01

Pin JWT Algorithm in Verification

High Risk
Threat: JWT algorithm confusion attack allows signature bypass

Recommendation

Explicitly restrict accepted algorithms during token verification. Never allow the algorithm to be derived from the token header alone.

const jwt = require('jsonwebtoken');

const verifyToken = (token) => {
  return jwt.verify(token, publicKey, {
    algorithms: ['RS256'], // Explicitly pin algorithm
    issuer: 'https://cognito-idp.us-east-1.amazonaws.com/YOUR_POOL_ID',
    audience: 'YOUR_CLIENT_ID'
  });
};

Additional Controls

  • Rotate signing keys quarterly via Cognito key rotation
  • Monitor for tokens with unexpected algorithm headers in ELK
AUTH-03

Implement Secure Token Storage

High Risk
Threat: XSS-based JWT theft enables session hijacking

Recommendation

Store tokens in HttpOnly cookies instead of localStorage. Implement Content Security Policy headers.

// Express.js cookie configuration
res.cookie('accessToken', token, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict',
  maxAge: 3600000 // 1 hour
});

CSP Header Configuration

Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' wss://your-domain.com
DATA-01

Enforce S3 Private Access

High Risk
Threat: Public bucket exposure leaks patient documents

Recommendation

Enable S3 Block Public Access at account level and enforce secure transport via bucket policy.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyInsecureTransport",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::meridian-pms-patient-docs",
        "arn:aws:s3:::meridian-pms-patient-docs/*"
      ],
      "Condition": {
        "Bool": { "aws:SecureTransport": "false" }
      }
    }
  ]
}
DATA-03

Implement Parameterized Queries

High Risk
Threat: SQL injection in patient search endpoints

Recommendation

Use parameterized queries exclusively. Enable MariaDB query logging for injection attempt detection.

// Using mysql2 with prepared statements
const searchPatients = async (searchTerm) => {
  const [rows] = await pool.execute(
    'SELECT id, name, dob FROM patients WHERE name LIKE ? OR mrn = ?',
    [`%${searchTerm}%`, searchTerm]
  );
  return rows;
};

Input Validation Layer

const Joi = require('joi');

const patientSearchSchema = Joi.object({
  query: Joi.string().max(100).pattern(/^[a-zA-Z0-9\s\-]+$/).required()
});
API-01

Implement Authorization Checks for IDOR Prevention

High Risk
Threat: Insecure Direct Object Reference allows cross-patient data access

Recommendation

Validate resource ownership on every request. Implement middleware that verifies the authenticated user has access to the requested patient record.

const authorizePatientAccess = async (req, res, next) => {
  const requestedPatientId = req.params.patientId;
  const userId = req.user.sub; // From JWT
  
  const hasAccess = await checkPatientAccess(userId, requestedPatientId);
  
  if (!hasAccess) {
    logger.warn('IDOR attempt', { userId, requestedPatientId, ip: req.ip });
    return res.status(403).json({ error: 'Access denied' });
  }
  next();
};

app.get('/api/patients/:patientId', authorizePatientAccess, getPatientHandler);
API-03

Secure Third-Party API Integration

High Risk
Threat: ScriptGuard API key compromise

Recommendation

Store API keys in AWS Secrets Manager with rotation. Implement request signing and IP allowlisting.

// Rotate keys and use short-lived tokens where supported
const getScriptGuardClient = async () => {
  const apiKey = await getSecretValue('meridian-pms/scriptguard/apikey');
  return axios.create({
    baseURL: 'https://api.scriptguard.io/v2',
    headers: {
      'X-API-Key': apiKey,
      'X-Request-ID': crypto.randomUUID()
    },
    timeout: 5000
  });
};

Network Controls

  • Configure VPC endpoints for outbound API calls
  • Implement egress filtering to allow only ScriptGuard IP ranges
  • Log all third-party API requests to ELK
RTC-01

Secure WebRTC TURN Server

High Risk
Threat: Unauthenticated TURN server abuse

Recommendation

Implement time-limited TURN credentials generated per session.

const generateTurnCredentials = (userId) => {
  const timestamp = Math.floor(Date.now() / 1000) + 3600; // 1 hour validity
  const username = `${timestamp}:${userId}`;
  const credential = crypto
    .createHmac('sha1', TURN_SECRET)
    .update(username)
    .digest('base64');
  
  return {
    urls: ['turn:turn.meridian-pms.com:443?transport=tcp'],
    username,
    credential
  };
};
INFRA-03

Secure GitHub Actions Workflows

High Risk
Threat: Workflow injection via malicious pull requests

Recommendation

Require approval for workflows from first-time contributors. Pin action versions to SHA.

# .github/workflows/deploy.yml
name: Deploy
on:
  push:
    branches: [main]

permissions:
  contents: read
  id-token: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production  # Requires approval
    steps:
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      - uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
        with:
          role-to-assume: arn:aws:iam::ACCOUNT:role/github-deploy
          aws-region: us-east-1
AUTH-02

Mitigate Cognito User Enumeration

Medium Risk
Threat: Differential response timing reveals valid usernames

Recommendation

Enable Cognito's PREVENT_USER_EXISTENCE_ERRORS setting.

aws cognito-idp update-user-pool-client \
  --user-pool-id us-east-1_XXXXX \
  --client-id YOUR_CLIENT_ID \
  --prevent-user-existence-errors ENABLED

Additional Controls

  • Constant-time comparison in custom auth Lambda triggers
  • Rate limit login attempts per source IP via WAF rules
AUTH-04

Implement Comprehensive Authentication Logging

Medium Risk
Threat: Insufficient auth failure logging prevents breach detection

Recommendation

Log all authentication events with structured fields for correlation. Ship to ELK with alerting.

const logAuthEvent = (event, req) => {
  logger.info({
    type: 'AUTH_EVENT',
    action: event.action,
    userId: event.userId || 'unknown',
    sourceIp: req.ip,
    userAgent: req.headers['user-agent'],
    timestamp: new Date().toISOString(),
    failureReason: event.reason || null
  });
};

Alerting Rules

  • >5 failed logins from single IP within 10 mins
  • Successful login from new geographic region
  • Retain auth logs minimum 6 years per HIPAA §164.312(b)
API-02

Implement API Rate Limiting

Medium Risk
Threat: Unrestricted API access enables resource exhaustion

Recommendation

Apply rate limits at both API Gateway and application layers using sliding window counters.

const rateLimit = require('express-rate-limit');

const apiLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 100,
  standardHeaders: true,
  legacyHeaders: false,
  keyGenerator: (req) => req.user?.sub || req.ip,
  handler: (req, res) => {
    logger.warn('Rate limit exceeded', { userId: req.user?.sub, ip: req.ip });
    res.status(429).json({ error: 'Too many requests' });
  }
});

app.use('/api/', apiLimiter);

Additional Controls

  • AWS WAF rate-based rules at 2,000 req/5 min per IP
  • Stricter limits on /api/patients/search at 20 req/min
RTC-02

Validate Socket.IO Connection Origins

Medium Risk
Threat: Cross-site Socket.IO hijacking via missing origin validation

Recommendation

Restrict Socket.IO connections to trusted origins and require JWT authentication on handshake.

const io = require('socket.io')(server, {
  cors: {
    origin: ['https://meridian-pms.com'],
    methods: ['GET', 'POST'],
    credentials: true
  }
});

io.use((socket, next) => {
  const token = socket.handshake.auth.token;
  try {
    const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
    socket.user = decoded;
    next();
  } catch (err) {
    logger.warn('Socket.IO auth failed', { ip: socket.handshake.address, error: err.message });
    next(new Error('Authentication required'));
  }
});
INFRA-01

Apply Least-Privilege Lambda IAM Roles

Medium Risk
Threat: Over-permissioned Lambda roles enable lateral movement

Recommendation

Create per-function IAM roles scoped to minimum required resources. Avoid wildcard permissions.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": "arn:aws:s3:::meridian-pms-patient-docs/lab-results/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue"
      ],
      "Resource": "arn:aws:secretsmanager:us-east-1:ACCOUNT:secret:meridian-pms/mariadb/prod-*"
    }
  ]
}

Additional Controls

  • Use IAM Access Analyzer to identify unused permissions
  • Enable CloudTrail for Lambda invocations
  • Review IAM policies quarterly
INFRA-02

Secure Prometheus Metrics Endpoint

Medium Risk
Threat: Unauthenticated Prometheus endpoint leaks system metadata

Recommendation

Place Prometheus behind an authentication proxy and restrict network access to monitoring VPC subnet.

server {
    listen 9090 ssl;
    server_name prometheus.internal.meridian-pms.com;

    ssl_certificate /etc/ssl/certs/prometheus.crt;
    ssl_certificate_key /etc/ssl/private/prometheus.key;

    location / {
        auth_basic "Prometheus";
        auth_basic_user_file /etc/nginx/.htpasswd;
        proxy_pass http://localhost:9091;
    }
}

Network Controls

  • Bind Prometheus to localhost (127.0.0.1:9091)
  • Restrict security group ingress to monitoring subnet CIDR only
  • Scrub sensitive labels from exported metrics using metric_relabel_configs

HIPAA Security Rule Mapping

HIPAA Requirement §164 Reference Current State Gap
Access Control §164.312(a)(1) Cognito + JWT implemented IDOR vulnerability (API-01) undermines access control
Audit Controls §164.312(b) ELK Stack deployed Insufficient auth failure logging (AUTH-04)
Integrity Controls §164.312(c)(1) TLS in transit stated SQL injection risk (DATA-03) threatens integrity
Transmission Security §164.312(e)(1) TLS/SSL configured WebRTC TURN lacks auth (RTC-01)
Person Authentication §164.312(d) 2FA via Cognito JWT algorithm confusion (AUTH-01) bypasses auth
Encryption §164.312(a)(2)(iv) At-rest encryption stated S3 bucket policy gaps (DATA-01)
Contingency Plan §164.308(a)(7) Not documented Backup/recovery procedures needed
Security Incident §164.308(a)(6) Prometheus monitoring No incident response playbook documented

Priority HIPAA Remediation Actions

Immediate
Address AUTH-01, DATA-01, API-01 to restore access control integrity
30 Days
Implement comprehensive audit logging covering all PHI access
60 Days
Document incident response procedures and conduct tabletop exercise
90 Days
Complete penetration test and remediate findings

Risk Summary

8
High Risk
Remediate before next release
7
Medium Risk
Plan remediation within 30 days
0
Low Risk
Overall Risk Posture
HIGH

Multiple unaddressed vulnerabilities in authentication and data protection create significant breach risk and HIPAA compliance gaps.

References

Document History

Version Date Author Changes
1.0 December 19, 2025 Security Architecture Team Initial threat model