8000 Overview · hrithiksaini99/MyFinances · GitHub
[go: up one dir, main page]

Skip to content

Security: hrithiksaini99/MyFinances

Security

SECURITY.md

Security Practices for MyFinances

Overview

MyFinances is a client-side personal finance tracking application with strong security practices. This document outlines the security measures implemented and best practices for deployment and usage.

Security Architecture

Client-Side Only (Default)

  • No Backend Server (default): All data is stored locally in the browser's localStorage
  • No Network Transmission: Financial data never leaves your machine
  • No API Calls: Eliminates server vulnerabilities
  • Offline Capable: Works without internet connection

Optional PostgreSQL Backend

An opt-in self-hosted Node.js + PostgreSQL backend adds multi-device sync with strong server-side security:

  • argon2id password hashing — industry-standard, tuned cost factors
  • Server-side sessions — opaque tokens hashed before storage; never stored in plain text
  • httpOnly / Secure / SameSite=Strict cookies — session token unreachable from JavaScript
  • CSRF double-submit tokens — every mutating request requires a matching csrf cookie + header pair
  • Rate limiting — login endpoint protected against brute force
  • New-password policy (NIST SP 800-63B rev 4) — 15–128 characters, no composition rules, rejects common, repetitive and context-based passwords on setup, reset and change; optional Have I Been Pwned k-anonymity breach check (SECURITY_CHECK_BREACHED_PASSWORDS, fails open); changing or resetting the password signs out other sessions. See server/README.md
  • See DEPLOYMENT.md for setup and server/README.md for architecture

Security Features

1. Input Validation & Sanitization

All user inputs are validated and sanitized before processing:

Text Input Sanitization (normalizeText)

// Removes dangerous characters
// Strips: <, >, ", `, control characters
// Applied to: account names, income names, debt names, etc.

Numeric Input Validation (sanitizeFiniteNumber)

// Validates numeric inputs
// Applies min/max bounds
// Prevents NaN and Infinity values
// Used for: amounts, interest rates, balances

Date Validation (sanitizeDateISO)

// Strict ISO date format validation (YYYY-MM-DD)
// Regex: /^\d{4}-\d{2}-\d{2}$/
// Validates date parsing

HTML Output Encoding (escapeHtml)

// Converts HTML special characters to entities:
// & → &amp;
// < → &lt;
// > → &gt;
// " → &quot;
// ' → &#39;

2. Cross-Site Scripting (XSS) Prevention

All user-provided data displayed in the DOM is HTML-encoded:

// Safe: User data is always escaped before rendering
<span class="acct-card-name">${escapeHtml(a.name)}</span>

// Dangerous pattern (NOT USED in this codebase):
<span>${a.name}</span>  // ❌ XSS vulnerability

Protection Methods:

  • Use escapeHtml() for all user data in innerHTML
  • Use textContent instead of innerHTML where possible
  • No dynamic script injection
  • No eval() usage
  • No Function() constructor usage

3. Content Security Policy (CSP)

Strong CSP header implemented in index.html:

default-src 'self';
script-src 'self' https://cdn.jsdelivr.net https://www.googletagmanager.com;
style-src 'self';
img-src 'self' data:;
font-src 'self';
connect-src 'self' https://cdn.jsdelivr.net https://www.google-analytics.com;
object-src 'none';
base-uri 'self';
form-action 'self'

Note: frame-ancestors 'none' is intentionally omitted from the meta tag — browsers ignore it there per spec. Add frame-ancestors 'none' to the server-level CSP HTTP header (see DEPLOYMENT.md) alongside X-Frame-Options: DENY for clickjacking protection.

Note: The googletagmanager.com/google-analytics.com origins support an opt-in, off-by-default Google Analytics integration for self-hosters (GA_MEASUREMENT_ID env var — see DEPLOYMENT.md's "Google Analytics (Optional)" section). They're allow-listed unconditionally so the feature can work when configured, but nothing loads or is contacted unless you set that variable.

Protection:

  • Restricts scripts to self, the trusted Chart.js CDN, and (only if you opt in) Google Analytics
  • Prevents inline scripts
  • Prevents frame embedding (clickjacking protection)
  • Blocks unsafe objects/embeds
  • Restricts form submissions

4. Data Import/Export Security

File Upload Protection

  • Size Limit: Maximum 2 MB (prevents memory exhaustion)
  • Format Validation: JSON only (via accept attribute)
  • Content Validation: Comprehensive sanitization on import

Import Process

1. File size check (MAX_IMPORT_BYTES = 2 MB)
2. JSON parsing (wrapped in try-catch)
3. Full data validation and re-sanitization
4. Type checking on all fields
5. Invalid records filtered out

Export Security

  • Clean JSON export (no sensitive metadata)
  • No credentials or tokens included
  • User has full control over exported data

5. Data Storage

LocalStorage

  • Scope: Same-origin policy enforced by browser
  • Encryption: Browser handles encryption at rest
  • Isolation: Other origins cannot access data
  • Format: Valid JSON only

No Sensitive Data Storage

  • ❌ No passwords
  • ❌ No API keys
  • ❌ No authentication tokens
  • ✅ Theme preference (non-sensitive)

6. No External Dependencies

  • Vanilla JavaScript: No npm packages to audit
  • No Third-Party Libraries: Except Chart.js from CDN (for visualization only)
  • No Vulnerable Dependencies: All code is self-contained
  • Code Review Easy: All source code is readable and auditable

Deployment Security

Adding HTTP Security Headers

When deploying MyFinances, add these HTTP security headers:

X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()

Example for Different Platforms:

Express.js

app.use((req, res, next) => {
    res.set('X-Content-Type-Options', 'nosniff');
    res.set('X-Frame-Options', 'DENY');
    res.set('X-XSS-Protection', '1; mode=block');
    res.set('Referrer-Policy', 'strict-origin-when-cross-origin');
    next();
});

Nginx

server {
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}

Apache

Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"

PowerShell HttpListener

$context.Response.AddHeader('X-Content-Type-Options', 'nosniff')
$context.Response.AddHeader('X-Frame-Options', 'DENY')
$context.Response.AddHeader('X-XSS-Protection', '1; mode=block')
$context.Response.AddHeader('Referrer-Policy', 'strict-origin-when-cross-origin')

HTTPS Deployment

For production deployment:

  1. Use HTTPS Only

    • Protects data in transit
    • Use valid SSL/TLS certificate
    • Redirect HTTP to HTTPS
  2. Strict-Transport-Security Header

    Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
    
  3. CORS Configuration

    • Only allow same-origin requests
    • Avoid Access-Control-Allow-Origin: *

Security Best Practices for Users

1. Browser Security

  • Keep browser updated to latest version
  • Use a modern browser with CSP support
  • Enable JavaScript (required for app)
  • Clear browser cache/data when done on shared computers

2. Data Backup

  • Regular Exports: Export data regularly as JSON backup
  • Secure Storage: Keep backups in secure locations
  • Multiple Copies: Maintain copies on different devices

3. Device Security

  • Use strong device password/PIN
  • Enable device encryption
  • Use reputable antivirus software
  • Lock device when not in use

4. Local Storage

  • Understand localStorage is readable by any JavaScript
  • Only use on trusted devices
  • Clear browser data if compromised
  • Never share device with untrusted users

Security Testing

The application includes automated security tests:

# Run security test suite
pytest tests/security/ -v

# Tests include:
# - XSS Prevention: HTML/script tag injection
# - CSP Compliance: No inline style or script violations
# - Input Validation: Special characters, bounds
# - Static Analysis: Code patterns, no hardcoded secrets

Test Coverage

  • ✓ XSS attack prevention
  • ✓ Input validation and bounds checking
  • ✓ Data persistence and restoration
  • ✓ File import sanitization
  • ✓ No console errors
  • ✓ JSON format validation

Repository & CI Governance

main is protected by two GitHub rulesets (issue #380, aligned with the BookWheel baseline):

Ruleset Enforces Bypass
Protect Default Branch - Force Push No force-pushes, no deletion of main None, not even admins
Protect Default Branch - Bypass Every change arrives through a pull request; required checks must pass on an up-to-date branch; CodeQL and Trivy code-scanning block new alerts of high or above; stale reviews are dismissed on push Admin, pull-request only: an override is possible but is recorded on the PR, and direct pushes are rejected
  • Required checks:
    • ci-complete: one job in ci.yml that waits on every CI job and fails if any failed or was cancelled. tests/features/test_ci_shard_coverage.py fails CI if a job is missing from it.
    • Analyze JavaScript (CodeQL).
    • trivy: blocks fixable CRITICAL/HIGH image vulnerabilities and hardcoded secrets.
    • dependency-review.
  • Approvals: the required count is 0. There is one maintainer, and GitHub doesn't allow approving your own PR. The owner reviews each PR before merging.
  • Never use the override to merge a red PR. Fix the failure or don't merge.
  • Secret scanning and push protection are enabled. Dependabot alerts and security updates are on.

Vulnerability Reporting

If you discover a security vulnerability:

  1. Do not create a public GitHub issue
  2. Do not share vulnerability details publicly
  3. Contact the repository owner privately
  4. Include steps to reproduce and impact assessment
  5. Wait for confirmation before public disclosure

Security Audit Results

Most Recent Audit: August 31, 2026

Summary

  • Risk Level: LOW
  • Status: PASSED
  • No Critical Vulnerabilities: YES

Key Findings

  • ✅ All input properly sanitized
  • ✅ No XSS vulnerabilities
  • ✅ Strong CSP implemented
  • ✅ Secure file upload handling
  • ✅ No dangerous code patterns
  • ✅ Client-side only (no server vulnerabilities)
  • ✅ No sensitive data exposure
  • ✅ Proper error handling

For full audit reports, see: docs/audit/security/

Security Improvements Completed

The following previously planned enhancements are now shipped:

  • ✅ Progressive Web App (PWA) — sw.js service worker for offline capability and app-shell caching
  • ✅ Optional server-side auth — argon2id + session cookies + CSRF for the Postgres backend

Remaining considerations:

  • localStorage encryption (browser-side, optional for highly sensitive deployments)
  • Password protection for JSON exports

Compliance

Standards Met

  • ✓ OWASP Top 10 Mitigation
  • ✓ CWE Coverage (input validation, XSS prevention)
  • ✓ CSP Level 3 Implementation

Privacy

  • ✓ No data collection by default
  • ✓ No tracking by default — self-hosters may opt their own instance into Google Analytics (see CSP section above)
  • ✓ No external API calls unless you enable that opt-in analytics or the optional self-hosted Postgres backend
  • ✓ Local storage only (unless the optional Postgres backend is configured)

Security Contacts

For security-related questions or concerns, please contact the repository maintainer.


Last Updated: August 31, 2026
Version: 1.1
Status: Production-Ready

There aren't any published security advisories

0