This document summarizes the complete implementation of the Missing Signature Domain Separation rule for GasGuard.
- ✅ Detect incomplete EIP-712 configs
- ✅ Warn developers
- ✅ Implementation scope:
rules/security/signatures/ - ✅ Acceptance criteria: Missing domain separation detected
packages/rules/src/security/signatures/
├── mod.rs # Module exports
├── missing_domain_separation.rs # Core rule implementation (300+ lines)
├── fixtures.rs # Test fixtures and code examples
└── README.md # Comprehensive documentation
- ✅
packages/rules/src/security/mod.rs- Added signatures module export - ✅
packages/rules/src/lib.rs- Added MissingDomainSeparationRule export
Rule Name: missing-domain-separation
Description: Detects signatures lacking proper EIP-712 domain separation. Missing domain separation enables replay attacks across different chains or contract contexts.
- Detects use of
ecrecover()without domain separation - Detects use of
ECDSA.recover()without domain separation - Severity: Critical
- Example pattern detected:
function recoverSigner(bytes32 hash, bytes memory sig) returns (address) { (uint8 v, bytes32 r, bytes32 s) = splitSignature(sig); return ecrecover(hash, v, r, s); // ❌ No domain separation! }
The rule detects several types of incomplete implementations:
a) Missing DOMAIN_TYPEHASH
function recoverSigner(...) {
return ecrecover(hash, v, r, s); // ❌ DOMAIN_TYPEHASH not defined
}b) Missing domainSeparator Computation
bytes32 constant DOMAIN_TYPEHASH = ...;
function recoverSigner(...) {
return ecrecover(hash, v, r, s); // ❌ DOMAIN_TYPEHASH defined but not used
}c) Missing Chain ID in Domain Separator
function computeDomainSeparator() returns (bytes32) {
return keccak256(abi.encode(
DOMAIN_TYPEHASH,
keccak256(bytes("MyApp")),
keccak256(bytes("1")),
// ❌ Missing: block.chainid
address(this)
));
}d) Incomplete EIP-712 Message Type Hash
function verify(...) {
if (keccak256(abi.encode(...)) && !hasTypehash) {
// ❌ Missing proper TYPEHASH definition for message
}
}// Pattern Detection
fn has_signature_verification(code: &str) -> bool
// Detects: ecrecover, ECDSA.recover, signature, _recover, recoverSigner
// Domain Separation Detection
fn has_domain_separation(code: &str) -> bool
// Detects: DOMAIN_TYPEHASH, domainSeparator, domain_separator, DOMAIN_SEPARATOR, EIP712DOMAIN
// Incomplete Configuration Detection
fn check_incomplete_eip712(code: &str) -> Vec<String>
// Returns list of detected issues:
// - Missing DOMAIN_TYPEHASH
// - Missing domainSeparator computation
// - Incomplete message type hash
// - Missing chain ID in domain separator
// Main Rule Implementation
impl Rule for MissingDomainSeparationRule
fn name() -> "missing-domain-separation"
fn description() -> "Detects signatures lacking proper EIP-712 domain separation..."
fn check(&self, ast: &[Item]) -> Vec<RuleViolation>The implementation includes 5 comprehensive unit tests:
Purpose: Verify detection of completely missing domain separation
Code: Signature verification with direct ecrecover() call
Expected Result: Critical violation detected
Purpose: Verify recognition of complete EIP-712 implementation Code: Full EIP-712 with DOMAIN_TYPEHASH, domainSeparator, chain ID, and digest computation Expected Result: No critical violations
Purpose: Verify detection of defined but unused domain separation Code: DOMAIN_TYPEHASH defined but recoverSigner doesn't use it Expected Result: Violation detected for missing domainSeparator computation
Purpose: Verify detection of missing chain ID
Code: Domain separator without block.chainid
Expected Result: High violation detected for chain ID absence
Purpose: Ensure robust pattern detection Tested Patterns:
ecrecoverdetectionECDSA.recoverdetectionDOMAIN_TYPEHASHdetectiondomainSeparatorvariations
Contents:
- ✅ Security risk explanation with real-world attack scenarios
- ✅ EIP-712 domain separation explanation with code examples
- ✅ 5 code examples showing:
- ❌ Complete absence of domain separation
- ❌ Incomplete implementations (5 different types)
- ✅ Correct manual implementation
- ✅ Correct using OpenZeppelin
- ✅ References to EIP-712 and OpenZeppelin documentation
- ✅ Recommended libraries section
- ✅ Integration examples
- ✅ Testing instructions
Provides reusable code snippets for testing:
- VULNERABLE_NO_DOMAIN_SEPARATION - Direct ecrecover with no domain
- VULNERABLE_DOMAIN_DEFINED_NOT_USED - Domain typehash defined but unused
- VULNERABLE_MISSING_CHAIN_ID - Domain separator without block.chainid
- VULNERABLE_DOMAIN_NOT_USED_IN_RECOVERY - Domain computed but not applied
- CORRECT_FULL_EIP712 - Manual EIP-712 implementation (200+ lines)
- CORRECT_OPENZEPPELIN_EIP712 - Using OpenZeppelin contracts
- VULNERABLE_ECDSA_RECOVER - OpenZeppelin ECDSA without domain
- VULNERABLE_NO_MESSAGE_TYPEHASH - Missing message type hash definition
Each fixture includes comments and is ready for copy-paste testing.
use gasguard_rules::{RuleEngine, MissingDomainSeparationRule};
// Create engine with the new rule
let engine = RuleEngine::new()
.add_rule(Box::new(MissingDomainSeparationRule));
// Analyze code
let violations = engine.analyze(solidity_code)?;
// Example violation output:
// RuleViolation {
// rule_name: "missing-domain-separation",
// description: "Signature verification detected without EIP-712 domain separation...",
// severity: ViolationSeverity::Critical,
// suggestion: "Implement EIP-712 domain separation by: 1. Define DOMAIN_TYPEHASH..."
// }| Severity | Condition | Example |
|---|---|---|
| Critical | Signature verification without any domain separation | ecrecover(hash, v, r, s) with no EIP-712 |
| High | Incomplete domain separation configuration | Missing DOMAIN_TYPEHASH, domainSeparator, or chain ID |
| Criteria | Status | Evidence |
|---|---|---|
| Detect incomplete EIP-712 configs | ✅ Complete | check_incomplete_eip712() method + 4 tests |
| Warn developers | ✅ Complete | Clear violation messages and suggestions |
Implementation scope: rules/security/signatures/ |
✅ Complete | Full implementation in correct directory |
| Missing domain separation detected | ✅ Complete | Critical and High violation detection |
This rule can be integrated into:
- GitHub Action: Runs on every PR to detect domain separation issues
- Local CLI:
gasguard scan --rules missing-domain-separation file.sol - API Endpoint: POST to analyze code for signature vulnerabilities
- IDE Integration: Real-time warnings for VSCode and other editors
Prevents:
- Cross-chain signature replay attacks
- Contract context replay attacks
- Type confusion exploits in signature verification
Affected Code:
- Smart contracts using custom signature verification
- DeFi protocols with permit functions
- MEV protection mechanisms
- DAO voting systems with signatures
- ✅ Follows Rust idioms and best practices
- ✅ Uses existing patterns from gasguard codebase
- ✅ Comprehensive documentation
- ✅ Test coverage for main scenarios
- ✅ Proper error handling
- ✅ Modular and extensible design
Potential future enhancements:
- Integration with GitHub Action marketplace
- API endpoint for remote analysis
- Integration with web dashboard
- Support for additional signature schemes (BLS, Schnorr)
- Support for other blockchains (Solana, Polkadot)
For issues or questions about this rule:
- See
README.mdin the signatures directory - Check
fixtures.rsfor code examples - Review test cases in
missing_domain_separation.rs - Consult EIP-712: https://eips.ethereum.org/EIPS/eip-712
Implementation Date: June 2, 2026 Rule Status: ✅ Ready for Production Test Status: ✅ All Tests Passing Documentation: ✅ Complete