This document describes security measures implemented in Tabee.
Tabee 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_scanjob - Coverage: Scans all files except
node_modules,.git, anddist - Action on detection: Pipeline fails if malware is detected
- Purpose: Detects hardcoded secrets, API keys, and credentials
- Configuration:
.github/workflows/ci.yml-gitleaks_scanjob - 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_auditjob - Severity: Fails on HIGH severity and above
- Tool:
audit-ciwith yarn
- Purpose: Ensures code quality and tracks test coverage
- Configuration:
.github/workflows/ci.yml-testjob - Tool: Vitest with coverage reporting
- Results: Coverage reports generated on every push
Tabee 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
falsefor 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 quantifiersSafe 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 lookaheadComprehensive 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
CONTAINSfor substring matching - Use
STARTS_WITH/ENDS_WITHfor prefix/suffix matching - Use
EXACTfor exact matching - Use
REGEXonly 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 Tabee, 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 parameterTitle 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