Mgid26/BugWatch · BugWatch.clar (~375 lines) · February 21, 2026
BugWatch is a decentralized bug bounty platform where security researchers submit vulnerability reports backed by STX stakes. Authorized AI oracles assess reports with severity ratings and confidence scores, and the contract handles bounty payouts, stake management, and reporter reputation tracking. An appeal mechanism lets reporters challenge AI decisions within a 144-block window.
CRITICAL C-01: Bounties Are Calculated But Never Paid Out
The finalize-ai-assessment function calculates a final-bounty, records it in the report's bounty field, and increments total-bounties-paid — but never actually transfers STX to the reporter. Only the original stake is returned.
;; Stake is returned:
(try! (return-stake reporter staked))
;; Bounty is tracked but never sent:
(var-set total-bounties-paid (+ (var-get total-bounties-paid) final-bounty))
;; No stx-transfer? for the bounty itself — nowhere in the contract
The entire economic incentive of the platform is non-functional. Reporters get back only their stake, never the promised bounty rewards. There is no bounty fund, no mechanism to deposit bounty funds, and no transfer to pay them.
Fix: Add a bounty fund (funded by project owners or a treasury), and add an stx-transfer? for the bounty amount in the verified branch.
HIGH H-01: No Mechanism to Remove AI Auditors
add-ai-auditor adds oracle principals but there is no remove-ai-auditor function. If an AI oracle's key is compromised, the owner cannot revoke access. A compromised oracle can verify fraudulent reports indefinitely, draining the stake pool.
Fix: Add a remove-ai-auditor function that sets the map value to false.
HIGH H-02: Appeal Window Anchored to Submission, Not Assessment
The appeal window is calculated from submission-height, not from when the AI assessment occurs:
(asserts! (< block-height (+ submission-block APPEAL-WINDOW)) ERR-APPEAL-WINDOW-CLOSED)
If the AI takes 140+ blocks to assess a report, the reporter has almost no time to file an appeal. In extreme cases, the window expires before assessment even happens, making appeals impossible.
Fix: Store the assessment block height and anchor the appeal window to it.
HIGH H-03: burn-stake Sends Funds to Owner, Not a Burn Address
(define-private (burn-stake (amount uint))
(as-contract (stx-transfer? amount tx-sender CONTRACT-OWNER))
)
Despite the name "burn," this transfers forfeited stakes to the contract owner. This creates a perverse incentive — the owner profits from rejected reports. Combined with the owner's control over AI oracle authorization, this could undermine trust in the entire platform.
Fix: Send to a true burn address, a DAO treasury, or split between community fund and protocol.
MEDIUM M-01: No Severity Validation in finalize-ai-assessment
The severity parameter accepts any string-ascii 20 value. A compromised oracle could pass arbitrary strings. The bounty calculation only handles "critical", "high", "medium" — anything else defaults to u50 (low). No explicit validation exists.
Fix: Assert severity is one of the expected values: "critical", "high", "medium", "low".
MEDIUM M-02: tx-sender Usage Vulnerable to Proxy Attacks
All authorization checks use tx-sender. If an AI auditor interacts through an intermediary contract, tx-sender is the intermediary — enabling impersonation of authorized oracles via wrapper contracts, or filing appeals on behalf of other reporters.
Fix: Use contract-caller where appropriate, or document the restriction against intermediary calls.
MEDIUM M-03: resolve-appeal Accepts Arbitrary Decision Strings
The decision parameter is unconstrained. Only "overturned" triggers stake return; anything else burns the stake. A typo like "overtruned" would silently burn the reporter's stake with no recourse.
Fix: Assert decision is either "overturned" or "upheld".
LOW L-01: Reputation Score Grows Unbounded
The reputation system adds +5 per verified report with no cap. A prolific reporter reaches arbitrarily high scores, which currently has no on-chain effect but could mislead off-chain consumers relying on the score for trust decisions.
LOW L-02: No Events Emitted for Appeals
file-appeal and resolve-appeal don't emit print events, unlike submissions and assessments. Off-chain indexers cannot track appeal activity without polling every report ID.
LOW L-03: Submission Fee Can Be Set to Zero
set-submission-fee has no minimum value check. Setting fee to u0 eliminates the spam deterrent that staking provides, defeating the platform's core economic design.
INFO I-01: No Re-assessment After Appeal Overturn
When an appeal is overturned (resolved in reporter's favor), the status changes to "verified-on-appeal" but no bounty calculation or payment occurs. The reporter gets their stake back but no bounty reward.
INFO I-02: update-reputation Return Value Unused
The private function returns a bool from map-set that is silently discarded in the begin blocks where it's called. Not a bug in Clarity, but worth noting.
INFO I-03: No Report Enumeration On-Chain
There's no way to enumerate all reports. Off-chain indexers must track the report-nonce and query each ID individually.
| Severity | Count |
|---|---|
| CRITICAL | 1 |
| HIGH | 3 |
| MEDIUM | 3 |
| LOW | 3 |
| INFO | 3 |
The most significant finding is that bounties are never actually paid — the core value proposition of the platform is non-functional. The contract calculates bounties, tracks them in state, but has no mechanism to fund or distribute them. Combined with irrevocable AI oracle access and a misaligned appeal window, the contract requires substantial fixes before production use.
The staking and reputation mechanics are conceptually sound. The appeal system is a good design choice. But without functional bounty payouts, the platform reduces to a staking-only system where reporters can only get their own money back.