Skip to content

[Security Audit] BizEscrow Smart Contracts — 6 Findings (1 Critical, 2 High, 3 Medium) #1

Description

@empek654

Security Audit: BizEscrow Smart Contracts — 6 Findings (1 Critical, 2 High, 3 Medium)

Target: laothu684/BizEscrow — Milestone-gated escrow & settlement protocol on Arc Testnet
Auditor: empek654 (sawonggaleng185@gmail.com)
Methodology: Manual code review + Foundry unit tests
Status: All 6 findings confirmed via PoC


Severity Overview

Severity Count Summary
🔴 Critical 1 type(uint256).max approval to mock contracts
🟠 High 2 No deadline enforcement, owner-controlled drain
🟡 Medium 3 Precision loss, trapped funds, job status reset

🔴 BIZ-01: Unlimited Token Approval (Critical)

File: BizEscrow.sol — Constructor (Line 242, 247)
CVSS 4.0: 9.3
Impact: Total loss of all deposited USDC if exploited

The constructor gives type(uint256).max USDC approval to both MockYieldPool and MockStableFX. If either mock is compromised, ALL deposited USDC can be drained.

Fix: Use exact approval amounts.


🟠 BIZ-02: Missing Deadline Check (High)

File: BizEscrow.sol — _releaseMilestone() (Line 489)
CVSS 4.0: 7.5
Impact: Seller cannot rely on deadline for protection

releaseMilestone() doesn't validate block.timestamp > e.deadline. Buyer can release funds after deadline passes.

Fix: Add require(block.timestamp <= e.deadline, "Deadline passed").


🟠 BIZ-03: Owner Can Drain All Funds (High)

File: BizEscrow.sol — setStableFX()
CVSS 4.0: 7.1
Impact: Owner key compromise = irreversible total loss

setStableFX(address) gives unlimited approval to ANY address.

Fix: Add timelock + multisig, remove auto-approval.


🟡 BIZ-04: Integer Precision Loss (Medium)

File: BizEscrow.sol — _releaseMilestone() (Line 504)

Proportional share calculation truncates fractional shares. Over multiple milestones, rounding error accumulates.


🟡 BIZ-05: Trapped Funds (Medium)

No sweep() function. Direct USDC transfers to contract are permanently stuck.


🟡 BIZ-06: Job Status Reset to OPEN (Medium)

File: BizEscrow.sol — claimRefund() (Line 731)

After refund, j.status = JobStatus.OPEN instead of REFUNDED/CANCELLED.


PoC

All bugs verified with Foundry tests. Full report attached.


Full report: bizescrow_security_report.pdf
Disclosed in good faith. 30-day disclosure window.

bizescrow_security_report.pdf

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions