feat: security audit fixes

This commit is contained in:
ZOMBIIIIIII
2026-05-13 00:17:32 +03:00
parent e87d178d71
commit 1498ed3431
31 changed files with 2198 additions and 339 deletions

View File

@@ -81,6 +81,20 @@ export async function initEnv(): Promise<void> {
return;
}
// H7 — HTTPS-only Vault enforce. Plaintext HTTP means master-key + AppRole secret_id
// travel through WAN unencrypted. Override via VAULT_ALLOW_INSECURE=true (only для local dev).
try {
const parsed = new URL(addr);
if (parsed.protocol !== 'https:' && p.VAULT_ALLOW_INSECURE !== 'true') {
throw new Error(`VAULT_ADDR must use https:// (got ${parsed.protocol}). Set VAULT_ALLOW_INSECURE=true only for local dev.`);
}
} catch (err: any) {
if (err.message?.includes('Invalid URL')) {
throw new Error(`VAULT_ADDR is malformed: ${addr}`);
}
throw err;
}
const token = await vaultAppRoleLogin(addr, roleId, secretId);
if (!token) {
logger.warn('Vault AppRole login failed, using .env fallback');
@@ -117,12 +131,15 @@ export async function initEnv(): Promise<void> {
},
jwt: {
...env.jwt,
issuer: s('JWT_ISSUER') || env.jwt.issuer,
audience: s('JWT_AUDIENCE') || env.jwt.audience,
// H17 — trim whitespace; пустая строка после trim → fallback на env
issuer: (s('JWT_ISSUER')?.trim() || env.jwt.issuer),
audience: (s('JWT_AUDIENCE')?.trim() || env.jwt.audience),
},
cors: {
origins: s('CORS_ORIGINS') ? s('CORS_ORIGINS')!.split(',') : env.cors.origins,
allowCredentials: secrets['CORS_ALLOW_CREDENTIALS'] !== 'false',
// H5 — fail-secure consistent with line 53: explicit 'true' required, default false.
// Раньше: `!== 'false'` → defaults TRUE if field missing/empty (security inversion).
allowCredentials: secrets['CORS_ALLOW_CREDENTIALS'] === 'true',
},
relayApiKey: s('RELAY_API_KEY') || env.relayApiKey,
tronApiKey: s('TRON_API_KEY') || env.tronApiKey,