Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
branches:
- 'main'
workflow_call:
pull_request:
branches:
- 'main'

concurrency:
group: validate-${{ github.ref_name }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,4 @@ storybook-static
.tmp/
.temp/
.claude/
private.pem
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"@caido/eslint-config": "^0.5.0",
"@caido/tailwindcss": "0.0.1",
"@vitejs/plugin-vue": "5.2.1",
"eslint": "^9.35.0",
"lodash": "^4.17.21",
"postcss-prefixwrap": "1.51.0",
"tailwindcss": "3.4.13",
"tailwindcss-primeui": "0.3.4",
Expand Down
3 changes: 2 additions & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@caido/sdk-backend": "^0.46.0"
"@caido/sdk-backend": "^0.46.0",
"@types/node": "^24.3.1"
}
}
102 changes: 83 additions & 19 deletions packages/backend/src/blacklists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,80 @@ export const USER_CONTENT_HOSTS = [
"googleusercontent.com",

// Blogger - Comprehensive subdomain list
"*.blogspot.ae", "*.blogspot.al", "*.blogspot.am", "*.blogspot.ba", "*.blogspot.be",
"*.blogspot.bg", "*.blogspot.bj", "*.blogspot.ca", "*.blogspot.cf", "*.blogspot.ch",
"*.blogspot.cl", "*.blogspot.co.at", "*.blogspot.co.id", "*.blogspot.co.il",
"*.blogspot.co.ke", "*.blogspot.co.nz", "*.blogspot.co.uk", "*.blogspot.co.za",
"*.blogspot.com", "*.blogspot.com.ar", "*.blogspot.com.au", "*.blogspot.com.br",
"*.blogspot.com.by", "*.blogspot.com.co", "*.blogspot.com.cy", "*.blogspot.com.ee",
"*.blogspot.com.eg", "*.blogspot.com.es", "*.blogspot.com.mt", "*.blogspot.com.ng",
"*.blogspot.com.tr", "*.blogspot.com.uy", "*.blogspot.cv", "*.blogspot.cz",
"*.blogspot.de", "*.blogspot.dk", "*.blogspot.fi", "*.blogspot.fr", "*.blogspot.gr",
"*.blogspot.hk", "*.blogspot.hr", "*.blogspot.hu", "*.blogspot.ie", "*.blogspot.in",
"*.blogspot.is", "*.blogspot.it", "*.blogspot.jp", "*.blogspot.kr", "*.blogspot.li",
"*.blogspot.lt", "*.blogspot.lu", "*.blogspot.md", "*.blogspot.mk", "*.blogspot.mr",
"*.blogspot.mx", "*.blogspot.my", "*.blogspot.nl", "*.blogspot.no", "*.blogspot.pe",
"*.blogspot.pt", "*.blogspot.qa", "*.blogspot.re", "*.blogspot.ro", "*.blogspot.rs",
"*.blogspot.ru", "*.blogspot.se", "*.blogspot.sg", "*.blogspot.si", "*.blogspot.sk",
"*.blogspot.sn", "*.blogspot.td", "*.blogspot.tw", "*.blogspot.ug", "*.blogspot.vn"
"*.blogspot.ae",
"*.blogspot.al",
"*.blogspot.am",
"*.blogspot.ba",
"*.blogspot.be",
"*.blogspot.bg",
"*.blogspot.bj",
"*.blogspot.ca",
"*.blogspot.cf",
"*.blogspot.ch",
"*.blogspot.cl",
"*.blogspot.co.at",
"*.blogspot.co.id",
"*.blogspot.co.il",
"*.blogspot.co.ke",
"*.blogspot.co.nz",
"*.blogspot.co.uk",
"*.blogspot.co.za",
"*.blogspot.com",
"*.blogspot.com.ar",
"*.blogspot.com.au",
"*.blogspot.com.br",
"*.blogspot.com.by",
"*.blogspot.com.co",
"*.blogspot.com.cy",
"*.blogspot.com.ee",
"*.blogspot.com.eg",
"*.blogspot.com.es",
"*.blogspot.com.mt",
"*.blogspot.com.ng",
"*.blogspot.com.tr",
"*.blogspot.com.uy",
"*.blogspot.cv",
"*.blogspot.cz",
"*.blogspot.de",
"*.blogspot.dk",
"*.blogspot.fi",
"*.blogspot.fr",
"*.blogspot.gr",
"*.blogspot.hk",
"*.blogspot.hr",
"*.blogspot.hu",
"*.blogspot.ie",
"*.blogspot.in",
"*.blogspot.is",
"*.blogspot.it",
"*.blogspot.jp",
"*.blogspot.kr",
"*.blogspot.li",
"*.blogspot.lt",
"*.blogspot.lu",
"*.blogspot.md",
"*.blogspot.mk",
"*.blogspot.mr",
"*.blogspot.mx",
"*.blogspot.my",
"*.blogspot.nl",
"*.blogspot.no",
"*.blogspot.pe",
"*.blogspot.pt",
"*.blogspot.qa",
"*.blogspot.re",
"*.blogspot.ro",
"*.blogspot.rs",
"*.blogspot.ru",
"*.blogspot.se",
"*.blogspot.sg",
"*.blogspot.si",
"*.blogspot.sk",
"*.blogspot.sn",
"*.blogspot.td",
"*.blogspot.tw",
"*.blogspot.ug",
"*.blogspot.vn",
];

// JavaScript hosts with known vulnerable libraries
Expand All @@ -57,7 +115,12 @@ export const VULNERABLE_JS_HOSTS = [
},
{
domain: "ajax.googleapis.com",
paths: ["/ajax/libs/angularjs/", "/ajax/libs/yui/", "/jsapi", "/ajax/services/feed/find"],
paths: [
"/ajax/libs/angularjs/",
"/ajax/libs/yui/",
"/jsapi",
"/ajax/services/feed/find",
],
risk: "AngularJS and JSONP vulnerabilities",
},

Expand Down Expand Up @@ -113,7 +176,8 @@ export class BlacklistManager {

// Check if path matches any vulnerable paths
if (
path &&
path !== undefined &&
path.trim() !== "" &&
vulnHost.paths.some((vulnPath) => path.includes(vulnPath))
) {
return { isVulnerable: true, risk: vulnHost.risk };
Expand Down Expand Up @@ -144,7 +208,7 @@ export class BlacklistManager {
results.push({
type: "vulnerable-js",
risk:
vulnCheck.risk ||
vulnCheck.risk ??
"Domain hosts known vulnerable JavaScript libraries",
});
}
Expand Down
44 changes: 29 additions & 15 deletions packages/backend/src/bypass-database.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
// CSP bypass database generated from data/csp-bypass-data.tsv
// This file is auto-generated - do not edit manually

import { readFileSync } from 'fs';
import { join } from 'path';
import { readFileSync } from "fs";
import { dirname, join } from "path";
import { fileURLToPath } from "url";

let cachedData: string | null = null;
let cachedCount: number | null = null;
let cachedData: string | undefined = undefined;
let cachedCount: number | undefined = undefined;

export const getCSPBypassData = (): string => {
if (cachedData === null) {
if (cachedData === undefined) {
try {
// Read the TSV file from the project root
const tsvPath = join(process.cwd(), 'data', 'csp-bypass-data.tsv');
cachedData = readFileSync(tsvPath, 'utf-8');
const tsvPath = join(process.cwd(), "data", "csp-bypass-data.tsv");
cachedData = readFileSync(tsvPath, "utf-8");
} catch (error) {
// Fallback to relative paths
try {
const tsvPath = join(__dirname, '..', '..', '..', 'data', 'csp-bypass-data.tsv');
cachedData = readFileSync(tsvPath, 'utf-8');
const currentDir = dirname(fileURLToPath(import.meta.url));
const tsvPath = join(
currentDir,
"..",
"..",
"..",
"data",
"csp-bypass-data.tsv",
);
cachedData = readFileSync(tsvPath, "utf-8");
} catch (fallbackError) {
// Final fallback to absolute path
try {
cachedData = readFileSync('/Users/ads/git/csp-auditor/data/csp-bypass-data.tsv', 'utf-8');
cachedData = readFileSync(
"/Users/ads/git/csp-auditor/data/csp-bypass-data.tsv",
"utf-8",
);
} catch (finalError) {
console.error('Failed to load TSV data from all paths:', finalError);
cachedData = 'Domain\tCode\n'; // Empty TSV with header
console.error(
"Failed to load TSV data from all paths: " + String(finalError),
);
cachedData = "Domain\tCode\n"; // Empty TSV with header
}
}
}
Expand All @@ -33,14 +47,14 @@ export const getCSPBypassData = (): string => {
};

export const getBypassCount = (): number => {
if (cachedCount === null) {
if (cachedCount === undefined) {
const data = getCSPBypassData();
const lines = data.trim().split('\n');
const lines = data.trim().split("\n");
cachedCount = Math.max(0, lines.length - 1); // Subtract 1 for header
}
return cachedCount;
};

// Legacy exports for backward compatibility
export const CSP_BYPASS_DATA = getCSPBypassData();
export const BYPASS_COUNT = getBypassCount();
export const BYPASS_COUNT = getBypassCount();
10 changes: 5 additions & 5 deletions packages/backend/src/csp-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export class CspParser {
if (parts.length === 0) continue;

const directiveName = parts[0]?.toLowerCase();
if (!directiveName) continue;
if (directiveName === undefined || directiveName.trim() === "") continue;
const directiveValues = parts.slice(1);

const directive: CspDirective = {
Expand Down Expand Up @@ -187,14 +187,14 @@ export class CspParser {
}
}

static computeEffectivePolicy(policies: CspPolicy[]): CspPolicy | null {
if (policies.length === 0) return null;
if (policies.length === 1) return policies[0] ?? null;
static computeEffectivePolicy(policies: CspPolicy[]): CspPolicy | undefined {
if (policies.length === 0) return undefined;
if (policies.length === 1) return policies[0] ?? undefined;

// For multiple policies, we need to intersect the directives
// This is a simplified approach - real CSP combination is complex
const firstPolicy = policies[0];
if (!firstPolicy) return null;
if (!firstPolicy) return undefined;

const effectivePolicy = { ...firstPolicy };
effectivePolicy.id = generateId();
Expand Down
Loading
Loading