From 94fdcb92b62db0671c43cc5f55ff866d138b84f4 Mon Sep 17 00:00:00 2001 From: Nafiu Ishaq <63783380+nafiuishaaq@users.noreply.github.com> Date: Mon, 1 Jun 2026 05:16:09 +0000 Subject: [PATCH 1/3] implemented the timestamp --- libs/engine/analyzers/solidity-analyzer.ts | 77 ++++++++++++++++++++++ tests/rules/solidity-rules.spec.ts | 45 +++++++++++++ 2 files changed, 122 insertions(+) diff --git a/libs/engine/analyzers/solidity-analyzer.ts b/libs/engine/analyzers/solidity-analyzer.ts index b157efd..0c09efc 100644 --- a/libs/engine/analyzers/solidity-analyzer.ts +++ b/libs/engine/analyzers/solidity-analyzer.ts @@ -142,6 +142,16 @@ export class SolidityAnalyzer extends BaseAnalyzer implements Analyzer { typical: 2000, }, }, + { + id: 'sol-013', + name: 'Unsafe Timestamp Dependency', + description: 'Detects use of block.timestamp or now in control flow and warns when critical logic depends on manipulable timestamps.', + severity: Severity.HIGH, + category: 'security', + enabled: true, + tags: ['security', 'timestamp', 'blockchain', 'time-dependency'], + documentationUrl: 'https://docs.gasguard.dev/rules/sol-013', + }, { id: 'sol-012', name: 'Missing Event Emission', @@ -316,6 +326,26 @@ export class SolidityAnalyzer extends BaseAnalyzer implements Analyzer { }, }))); } + + // Rule: sol-013 - Unsafe Timestamp Dependency + if (this.isRuleEnabled('sol-013', config)) { + const timestampDependencies = this.detectTimestampDependencies(code); + findings.push(...timestampDependencies.map(location => ({ + ruleId: 'sol-013', + message: location.message, + severity: this.getRuleSeverity('sol-013', config), + location: { + file: filePath, + startLine: location.startLine, + endLine: location.endLine, + }, + suggestedFix: { + description: 'Avoid using block.timestamp or now for critical control flow. Use a secure timelock, on-chain delay based on block.number, or an oracle-backed time source.', + codeSnippet: 'require(block.timestamp >= unlockTime, "Too early"); // avoid relying on timestamp for security-critical decisions', + documentationUrl: 'https://docs.gasguard.dev/rules/sol-013', + }, + }))); + } // Rule: sol-008 - Unsafe External Calls if (this.isRuleEnabled('sol-008', config)) { @@ -609,6 +639,53 @@ export class SolidityAnalyzer extends BaseAnalyzer implements Analyzer { return findings; } + private detectTimestampDependencies( + code: string, + ): Array<{ startLine: number; endLine: number; message: string }> { + const findings: Array<{ startLine: number; endLine: number; message: string }> = []; + const lines = code.split('\n'); + let inBlockComment = false; + + const timestampPattern = /\b(?:block\.timestamp|now)\b/; + const eventEmissionPattern = /\bemit\b/; + + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + const trimmed = line.trim(); + + if (trimmed.startsWith('/*') || trimmed.startsWith('/**')) { + inBlockComment = true; + } + if (inBlockComment) { + if (trimmed.includes('*/')) { + inBlockComment = false; + } + continue; + } + + if (trimmed.startsWith('//')) { + continue; + } + + if (!timestampPattern.test(line)) { + continue; + } + + if (eventEmissionPattern.test(line)) { + continue; + } + + findings.push({ + startLine: i + 1, + endLine: i + 1, + message: + 'Unsafe reliance on block.timestamp/now detected. Block timestamps are manipulable by miners, so avoid using them for critical control flow.', + }); + } + + return findings; + } + private detectInsecureFallbackFunctions(code: string): Array<{ startLine: number; endLine: number }> { const findings: Array<{ startLine: number; endLine: number }> = []; const lines = code.split('\n'); diff --git a/tests/rules/solidity-rules.spec.ts b/tests/rules/solidity-rules.spec.ts index 0ff0759..0e26a59 100644 --- a/tests/rules/solidity-rules.spec.ts +++ b/tests/rules/solidity-rules.spec.ts @@ -105,6 +105,51 @@ contract SecureBank is ReentrancyGuard { }); }); + describe('sol-013: Unsafe Timestamp Dependency', () => { + it('should detect unsafe reliance on block.timestamp and now in critical logic', async () => { + const code = ` +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract TimeSensitive { + uint256 public deadline; + + function bid() external { + require(block.timestamp <= deadline, "Auction expired"); + // bidding logic + } + + function recordStart() external { + uint256 startTime = now; + // start logic + } +} +`; + + const result = await analyzer.analyze(code, 'time-sensitive.sol'); + RuleAssertions.assertHasFinding(result.findings, 'sol-013'); + RuleAssertions.assertFindingSeverity(result.findings, 'sol-013', 'high'); + }); + + it('should not flag block.timestamp when used only for event emission', async () => { + const code = ` +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract LogTimestamp { + event Timestamped(uint256 timestamp); + + function log() external { + emit Timestamped(block.timestamp); + } +} +`; + + const result = await analyzer.analyze(code, 'timestamp-log.sol'); + RuleAssertions.assertNotHasFinding(result.findings, 'sol-013'); + }); + }); + describe('Rule Assertions', () => { it('should provide helpful assertion messages', async () => { const code = ` From 16f0903d72d924e3619cf84c1a033efd6ef6f07c Mon Sep 17 00:00:00 2001 From: Nafiu Ishaq <63783380+nafiuishaaq@users.noreply.github.com> Date: Mon, 1 Jun 2026 05:20:59 +0000 Subject: [PATCH 2/3] implemented the tx origin --- libs/engine/analyzers/solidity-analyzer.ts | 72 +++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/libs/engine/analyzers/solidity-analyzer.ts b/libs/engine/analyzers/solidity-analyzer.ts index 0c09efc..d384110 100644 --- a/libs/engine/analyzers/solidity-analyzer.ts +++ b/libs/engine/analyzers/solidity-analyzer.ts @@ -152,6 +152,16 @@ export class SolidityAnalyzer extends BaseAnalyzer implements Analyzer { tags: ['security', 'timestamp', 'blockchain', 'time-dependency'], documentationUrl: 'https://docs.gasguard.dev/rules/sol-013', }, + { + id: 'sol-014', + name: 'Insecure tx.origin Authentication', + description: 'Detects tx.origin usage in authentication or authorization checks and suggests using msg.sender instead.', + severity: Severity.HIGH, + category: 'security', + enabled: true, + tags: ['security', 'authentication', 'tx-origin', 'msg-sender'], + documentationUrl: 'https://docs.gasguard.dev/rules/sol-014', + }, { id: 'sol-012', name: 'Missing Event Emission', @@ -346,6 +356,26 @@ export class SolidityAnalyzer extends BaseAnalyzer implements Analyzer { }, }))); } + + // Rule: sol-014 - Insecure tx.origin Authentication + if (this.isRuleEnabled('sol-014', config)) { + const txOriginFindings = this.detectTxOriginUsage(code); + findings.push(...txOriginFindings.map(location => ({ + ruleId: 'sol-014', + message: location.message, + severity: this.getRuleSeverity('sol-014', config), + location: { + file: filePath, + startLine: location.startLine, + endLine: location.endLine, + }, + suggestedFix: { + description: 'Use msg.sender for authentication and authorization checks instead of tx.origin to prevent phishing and contract-based attacks.', + codeSnippet: 'require(msg.sender == owner, "Unauthorized");', + documentationUrl: 'https://docs.gasguard.dev/rules/sol-014', + }, + }))); + } // Rule: sol-008 - Unsafe External Calls if (this.isRuleEnabled('sol-008', config)) { @@ -650,7 +680,7 @@ export class SolidityAnalyzer extends BaseAnalyzer implements Analyzer { const eventEmissionPattern = /\bemit\b/; for (let i = 0; i < lines.length; i++) { - let line = lines[i]; + const line = lines[i]; const trimmed = line.trim(); if (trimmed.startsWith('/*') || trimmed.startsWith('/**')) { @@ -686,6 +716,46 @@ export class SolidityAnalyzer extends BaseAnalyzer implements Analyzer { return findings; } + private detectTxOriginUsage( + code: string, + ): Array<{ startLine: number; endLine: number; message: string }> { + const findings: Array<{ startLine: number; endLine: number; message: string }> = []; + const lines = code.split('\n'); + let inBlockComment = false; + + const txOriginPattern = /\btx\.origin\b/; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const trimmed = line.trim(); + + if (trimmed.startsWith('/*') || trimmed.startsWith('/**')) { + inBlockComment = true; + } + if (inBlockComment) { + if (trimmed.includes('*/')) { + inBlockComment = false; + } + continue; + } + + if (trimmed.startsWith('//')) { + continue; + } + + if (txOriginPattern.test(line)) { + findings.push({ + startLine: i + 1, + endLine: i + 1, + message: + 'Insecure tx.origin authentication detected. Use msg.sender instead of tx.origin for authorization checks.', + }); + } + } + + return findings; + } + private detectInsecureFallbackFunctions(code: string): Array<{ startLine: number; endLine: number }> { const findings: Array<{ startLine: number; endLine: number }> = []; const lines = code.split('\n'); From 166be37fc3d71c444f262dc6d7941d4dc708a440 Mon Sep 17 00:00:00 2001 From: Nafiu Ishaq <63783380+nafiuishaaq@users.noreply.github.com> Date: Mon, 1 Jun 2026 05:21:01 +0000 Subject: [PATCH 3/3] implemented the tx origin --- tests/rules/solidity-rules.spec.ts | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/rules/solidity-rules.spec.ts b/tests/rules/solidity-rules.spec.ts index 0e26a59..aef41a4 100644 --- a/tests/rules/solidity-rules.spec.ts +++ b/tests/rules/solidity-rules.spec.ts @@ -148,6 +148,53 @@ contract LogTimestamp { const result = await analyzer.analyze(code, 'timestamp-log.sol'); RuleAssertions.assertNotHasFinding(result.findings, 'sol-013'); }); + + it('should detect insecure tx.origin authentication usage', async () => { + const code = ` +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract OriginAuth { + address public owner; + + constructor() { + owner = msg.sender; + } + + function adminAction() external { + require(tx.origin == owner, "Not authorized"); + // sensitive logic + } +} +`; + + const result = await analyzer.analyze(code, 'origin-auth.sol'); + RuleAssertions.assertHasFinding(result.findings, 'sol-014'); + RuleAssertions.assertFindingMessage(result.findings, 'sol-014', 'tx.origin'); + }); + + it('should not flag msg.sender authentication', async () => { + const code = ` +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract SenderAuth { + address public owner; + + constructor() { + owner = msg.sender; + } + + function adminAction() external { + require(msg.sender == owner, "Not authorized"); + // sensitive logic + } +} +`; + + const result = await analyzer.analyze(code, 'sender-auth.sol'); + RuleAssertions.assertNotHasFinding(result.findings, 'sol-014'); + }); }); describe('Rule Assertions', () => {