This document describes security measures implemented in Tab Modifier.
Tab Modifier uses multiple security scanning tools in the CI/CD pipeline to ensure code quality and security:
- Purpose: Detects viruses, trojans, and other malware in the codebase
- Frequency: On every push to any branch
- Configuration:
.github/workflows/ci.yml
-clamav_malware_scan
job - Coverage: Scans all files except
node_modules
,.git
, anddist
- Action on detection: Pipeline fails if malware is detected
- Purpose: Detects security vulnerabilities and code quality issues
- Configuration:
.github/workflows/ci.yml
-semgrep_scan
job - Results: Uploaded to GitHub Security Dashboard as SARIF
- Purpose: Advanced semantic code analysis for security vulnerabilities
- Configuration:
.github/workflows/ci.yml
-codeql_sast
job - Queries:
security-extended
andsecurity-and-quality
- Results: Uploaded to GitHub Security Dashboard
- Purpose: Detects hardcoded secrets, API keys, and credentials
- Configuration:
.github/workflows/ci.yml
-gitleaks_scan
job - Action: Official
gitleaks/gitleaks-action@v2
- Scope: Full git history scan (
fetch-depth: 0
) - Results: Uploaded to GitHub Security Dashboard as SARIF
- Action on detection: Pipeline fails if secrets are found
- Purpose: Checks for known vulnerabilities in npm/yarn dependencies
- Configuration:
.github/workflows/ci.yml
-dependency_audit
job - Severity: Fails on HIGH severity and above
- Tool:
audit-ci
with yarn
Tab Modifier allows users to create rules with regular expressions to match URLs. User-controlled regex patterns can potentially be exploited to cause ReDoS attacks, where malicious regex patterns with catastrophic backtracking can freeze the browser tab.
We've implemented multi-layered protection against ReDoS attacks:
The _isRegexPatternSafe()
function validates regex patterns before execution:
- Nested Quantifiers: Blocks patterns like
(a+)+
,(a*)*
,(a{1,5})+
that cause exponential backtracking - Consecutive Quantifiers: Blocks patterns like
a**
,a+*
that are invalid or dangerous - Overlapping Alternatives: Blocks patterns like
(a|a)*
,(x+|x+y+)*
that create unnecessary backtracking - Length Limits: Rejects patterns longer than 1000 characters
- Syntax Validation: Ensures the pattern is a valid regex
The _safeRegexTestSync()
function:
- Validates the pattern before execution
- Catches and logs any execution errors
- Returns
false
for unsafe patterns instead of executing them
Instead of using new RegExp(pattern).test(url)
directly, always use:
import { _safeRegexTestSync } from './regex-safety.ts';
// Safe regex execution
const matches = _safeRegexTestSync(userPattern, url);
Dangerous patterns that are blocked:
(a+)+ # Nested quantifiers
(a*)* # Nested quantifiers
(a|a)* # Overlapping alternatives
(x+|x+y+)* # Overlapping alternatives with quantifiers
a++ # Consecutive quantifiers
Safe patterns that are allowed:
example\.com # Simple literal match
^https://[a-z]+\.example\.com # Character classes with quantifiers
[0-9]{1,4} # Bounded quantifiers
(?!MOUNCE).*version= # Negative lookahead
Comprehensive tests are in src/common/regex-safety.test.js
covering:
- Safe pattern validation
- Dangerous pattern detection and blocking
- Real-world regex patterns from existing rules
- Edge cases and error handling
-
Prefer simpler detection methods when possible:
- Use
CONTAINS
for substring matching - Use
STARTS_WITH
/ENDS_WITH
for prefix/suffix matching - Use
EXACT
for exact matching - Use
REGEX
only when pattern matching is truly needed
- Use
-
Write safe regex patterns:
- Avoid nested quantifiers
- Use bounded quantifiers (
{1,5}
) instead of unbounded (*
,+
) - Keep patterns as simple as possible
- Test patterns with the safety validator
-
Document complex patterns:
- Add comments explaining what the pattern matches
- Include test cases for complex patterns
The url_matcher
and title_matcher
features allow users to extract parts of URLs and page titles using regular expressions with capture groups. When regex patterns don't use anchors (^
for start, $
for end), they can match anywhere in the input string, potentially causing unexpected behavior.
In Tab Modifier, url_matcher
and title_matcher
are used to extract content for display in tab titles, not for security-critical validation like URL redirection or authentication. Therefore, missing anchors here represent a usability concern rather than a security vulnerability.
However, to prevent unexpected matches and follow security best practices, we recommend using anchored patterns.
Unanchored pattern (may match unexpectedly):
https:\/\/example\.com\/(.+)
# Could match: "evil.com?redirect=https://example.com/test"
Anchored pattern (matches precisely):
^https:\/\/example\.com\/(.+)
# Only matches URLs starting with https://example.com/
URL Matcher for GitHub repositories:
^https:\/\/github\.com\/([A-Za-z0-9_-]+)\/([A-Za-z0-9_-]+)
URL Matcher for query parameters:
[?&]date=([0-9]{4}-[0-9]{2}-[0-9]{2})
# Note: This doesn't need ^ anchor as we're matching a specific parameter
Title Matcher with full anchors:
^[a-z]*@gmail\.com$
For patterns that specifically target substrings (like query parameters or path segments), anchors may not be needed:
# Extracting query parameter - no anchor needed
[?&]id=([0-9]+)
# Extracting date from URL - no anchor needed
date=([0-9]{4}-[0-9]{2}-[0-9]{2})
The regex safety checks in src/content.js
already validate patterns before execution. To enhance this:
- Pattern Validation: The
isRegexSafe()
function checks for dangerous patterns - Safe Execution: The
createSafeRegex()
function creates validated regex instances - Error Handling: All regex operations are wrapped in try-catch blocks
-
Use anchors (
^
,$
) when matching complete URLs or titles✅ ^https:\/\/example\.com\/path$ ❌ https:\/\/example\.com\/path
-
Be specific with your patterns
✅ ^https:\/\/github\.com\/[A-Za-z0-9_-]+\/[A-Za-z0-9_-]+ ❌ .+github.com.+
-
Use character classes instead of wildcards when possible
✅ [A-Za-z0-9_-]+ ❌ .+
-
Test your patterns with the regex safety validator
- Patterns are automatically validated before use
- Check browser console for validation warnings
-
Consider the use case
- For extracting specific parts: anchors may be optional
- For matching the entire URL/title: always use anchors