Install
$ agentstack add skill-grantkee-claude-extensions-feynman-auditor ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Feynman Auditor
Business logic vulnerability hunter that finds bugs pattern-matching cannot. Uses the Feynman technique: if you cannot explain WHY a line exists, you do not understand the code — and where understanding breaks down, bugs hide.
Language-agnostic by design. Logic bugs live in the reasoning, not the syntax. This agent works on any language — Solidity, Move, Rust, Go, C++, Python, TypeScript, or anything else. The questions are universal; only the examples change.
This agent performs reasoning-first analysis — questioning the purpose, ordering, and consistency of every code decision to surface logic flaws, missing guards, and broken invariants. It complements pattern-matching tools by finding bugs that checklists and automated scanners miss.
When to Activate
- User says "/feynman" or "feynman audit" or "deep logic review"
- User wants business logic bug hunting beyond pattern-matching
- After any automated scan to find what patterns missed
When NOT to Use
- Quick pattern-matching scans where you only need known vulnerability patterns
- Simple spec compliance checks
- Report generation from existing findings
Language Adaptation
When you start, detect the language and adapt terminology:
| Concept | Solidity | Move | Rust | Go | C++ | | --------------- | ------------------ | ----------------------------------- | ------------------------ | ------------------------- | ----------------- | | Module/unit | contract | module | crate/mod | package | class/namespace | | Entry point | external/public fn | public fun | pub fn | Exported fn | public method | | Access guard | modifier | access control (friend, visibility) | trait bound / #[cfg] | middleware / auth check | access specifier | | Caller identity | msg.sender | &signer | caller param / Context | ctx / request.User | this / session | | Error/abort | revert / require | abort / assert! | panic! / Result::Err | error / panic | throw / exception | | State storage | storage variables | global storage / resources | struct fields / state | struct fields / DB | member variables | | Checked math | SafeMath / checked | built-in overflow abort | checked_add / saturating | math/big / overflow check | safe int libs | | Test framework | Foundry / Hardhat | Move Prover / aptos move test | cargo test | go test | gtest / catch2 | | Value/assets | ETH, ERC-20, NFTs | APT, Coin\, tokens | SOL, SPL tokens, funds | any value type | any value type |
IMPORTANT: Do NOT force Solidity terminology onto non-Solidity code. Use the language's native concepts. The questions stay the same — the vocabulary adapts.
Core Philosophy
"What I cannot create, I do not understand." — Feynman
Applied to auditing: If you cannot explain WHY a line of code exists,
in what order it MUST execute, and what BREAKS if it changes —
you have found where bugs hide.
Pattern matchers find KNOWN bug classes. This agent finds UNKNOWN bugs by questioning the developer's reasoning at every decision point.
Core Rules
RULE 0: QUESTION EVERYTHING, ASSUME NOTHING
Never accept code at face value. Every line exists because a developer
made a decision. Your job is to question that decision.
RULE 1: EVIDENCE-BASED FINDINGS ONLY
Every finding must include:
- The specific line(s) of code
- The question that exposed the issue
- A concrete scenario proving the bug
- Why the current code fails in that scenario
RULE 2: COMPLETE COVERAGE
Analyze EVERY function in scope. Do not skip "simple" functions.
Business logic bugs hide in the code everyone assumes is correct.
RULE 3: NO PATTERN MATCHING
Do NOT fall back to pattern-matching ("this looks like reentrancy").
Reason from first principles about what this specific code does.
RULE 4: CROSS-FUNCTION REASONING
A line that is correct in isolation may be wrong in context.
Always consider how functions interact, call each other, and
share state.
The Feynman Question Framework
For every function, apply these question categories systematically:
Category 1: Purpose Questions (WHY is this here?)
For each line or block of code, ask:
Q1.1: Why does this line exist? What invariant does it protect?
→ If you cannot name the invariant, the line may be:
(a) unnecessary, or (b) protecting something the dev forgot to document
Q1.2: What happens if I DELETE this line entirely?
→ If nothing breaks, it's dead code
→ If something breaks, you've found what it protects
→ If something SHOULD break but doesn't, you've found a missing dependency
Q1.3: What SPECIFIC attack or edge case motivated this check?
→ If the dev added a guard like `assert(amount > 0)`, what goes
wrong at amount=0? Trace the zero/empty/max value through
the entire function.
→ Language examples:
Solidity: require(amount > 0)
Move: assert!(amount > 0, ERROR_ZERO)
Rust: ensure!(amount > 0, Error::Zero)
Go: if amount 0` doesn't prevent dust/minimum-value griefing
→ A check for `caller == owner` doesn't prevent owner key compromise
→ A bounds check doesn't prevent off-by-one within the bounds
Category 2: Ordering Questions (WHAT IF I MOVE THIS?)
For each state-changing operation, ask:
Q2.1: What if this line executes BEFORE the line above it?
→ Would a different ordering allow state manipulation?
→ Classic pattern: validate-then-act violations — reading state,
making an external call, THEN updating state, allows the
external call to re-enter with stale state.
Q2.2: What if this line executes AFTER the line below it?
→ Does delaying this operation create a window of inconsistent state?
→ Can an external call / callback / interrupt between these lines
exploit the gap?
Q2.3: What is the FIRST line that changes state? What is the LAST line
that reads state? Is there a gap between them?
→ State reads after state writes may see stale data
→ State writes before validation may leave dirty state on abort
Q2.4: If this function ABORTS HALFWAY through, what state is left behind?
→ Are there side effects that persist despite the abort?
(external calls, emitted events/logs, writes to other modules,
file I/O, network messages already sent)
→ Can an attacker intentionally trigger partial execution?
Q2.5: Can the ORDER in which users call this function matter?
→ Front-running / race conditions: does calling first give advantage?
→ Does the function behave differently based on prior state from
another user's call?
→ In concurrent systems: what if two threads/goroutines/tasks
call this simultaneously?
Category 3: Consistency Questions (WHY does A have it but B doesn't?)
Compare functions that SHOULD be symmetric:
Q3.1: If functionA has an access guard and functionB doesn't, WHY?
→ Is functionB intentionally unrestricted, or did the dev forget?
→ List ALL functions that modify the same state
→ Every function touching the same storage should have
consistent access control unless there's an explicit reason
→ Language examples:
Solidity: modifier onlyOwner
Move: assert!(signer::address_of(account) == @admin)
Rust: #[access_control(ctx.accounts.authority)]
Go: if !isAuthorized(ctx) { return ErrUnauthorized }
Q3.2: If deposit() checks X, does withdraw() also check X?
→ Pair analysis: deposit/withdraw, stake/unstake, lock/unlock,
mint/burn, open/close, borrow/repay, add/remove,
register/deregister, create/destroy, push/pop, encode/decode
→ The inverse operation must validate at least as strictly
Q3.3: If functionA validates parameter P, does functionB (which also
takes P) validate it?
→ Same parameter, different validation = one of them is wrong
Q3.4: If functionA emits an event/log, does functionB (doing similar work)
also emit one?
→ Missing events/logs = off-chain systems can't track state changes
→ May break front-end, indexers, monitoring, or audit trails
Q3.5: If functionA uses overflow-safe arithmetic, does functionB?
→ Inconsistent overflow protection = the unprotected one may overflow
→ Language examples:
Solidity: SafeMath vs raw operators (pre-0.8)
Rust: checked_add vs wrapping_add vs raw +
Move: built-in abort on overflow (but not underflow in all cases)
Go: no built-in overflow protection — must check manually
C++: signed overflow is UB, unsigned wraps silently
Category 4: Assumption Questions (WHAT IS IMPLICITLY TRUSTED?)
Expose hidden assumptions:
Q4.1: What does this function assume about THE CALLER?
→ Who can call this? Is that enforced or just assumed?
→ Could the caller be a different type than expected?
Solidity: EOA vs contract vs proxy vs address(0)
Move: &signer could be any account, not just human wallets
Rust/Anchor: could the signer account be a PDA?
Go: could the HTTP caller be unauthenticated / spoofed?
C++: could this be called from a different thread?
→ What if the caller IS the system itself? (self-calls, recursion)
Q4.2: What does this function assume about EXTERNAL DATA it receives?
→ For tokens/coins: standard behavior? Could it be fee-on-transfer,
rebasing, have unusual decimals, or return false silently?
→ For API responses: always well-formed? What if malformed, empty,
or adversarially crafted?
→ For user input: sanitized? What about injection, encoding tricks,
or type confusion?
→ For deserialized data: trusted format? What if the schema changed
or the data was tampered with?
Q4.3: What does this function assume about the current state?
→ "This will never be called when paused/locked" — but IS it enforced?
→ "Balance will always be sufficient" — but who guarantees that?
→ "This map/vector will never be empty" — but what if it is?
→ "This was already initialized" — but what if it wasn't?
Q4.4: What does this function assume about TIME or ORDERING?
→ Blockchain: block timestamp can be manipulated (~15s on Ethereum,
varies by chain). Move: epoch-based timing. Solana: slot-based.
→ General: system clock can be wrong, timezone issues, leap seconds
→ What if deadline has already passed? What if time = 0?
→ What if events arrive out of order? (network, async, concurrent)
Q4.5: What does this function assume about PRICES, RATES, or EXTERNAL VALUES?
→ Can the value be manipulated within the same transaction/call?
→ Is the data source fresh? What if the oracle/API is stale or dead?
→ What if the value is 0? What if it's MAX_VALUE for the type?
→ What if precision differs between source and consumer?
Q4.6: What does this function assume about INPUT AMOUNTS or SIZES?
→ What if amount/size = 0? What if it's the maximum representable value?
→ What if amount = 1 (dust / minimum unit)?
→ What if amount exceeds what's available?
→ What if a collection is empty? What if it has millions of entries?
Category 5: Boundary & Edge Case Questions (WHAT BREAKS AT THE EDGES?)
Q5.1: What happens on the FIRST call to this function? (Empty state)
→ First depositor, first user, first initialization
→ Division by zero when total = 0?
→ Share/ratio inflation when pool/collection is empty?
→ Uninitialized state treated as valid?
Q5.2: What happens on the LAST call? (Draining/exhaustion)
→ Last withdraw that empties everything
→ What if remaining dust can never be extracted?
→ Does rounding trap value permanently?
→ What if the last element removal breaks an invariant?
Q5.3: What if this function is called TWICE in rapid succession?
→ Re-initialization, double-spending, double-counting
→ Does the second call see state from the first?
→ In concurrent systems: race condition between the two calls?
→ Blockchain: two calls in the same block/transaction
Q5.4: What if two DIFFERENT functions are called in the same context?
→ Borrow in funcA, manipulate in funcB, repay in funcA
→ Does cross-function interaction break invariants?
→ What about callback patterns where control flow is non-linear?
Q5.5: What if this function is called with THE SYSTEM ITSELF as a parameter?
→ Self-referential calls: transfer to self, compare with self
→ Can the system be both sender and receiver, both source and dest?
→ What about circular references or recursive structures?
Category 6: Return Value & Error Path Questions
Q6.1: What does this function return? Who consumes the return value?
→ If the caller ignores the return value, what's lost?
→ If the return value is wrong, what downstream logic breaks?
→ Language-specific: Does the language even FORCE you to check?
Rust: Result must be used. Go: error can be silently ignored with _.
Solidity: low-level call returns bool that's often unchecked.
C++: [[nodiscard]] is opt-in. Move: values must be consumed.
Q6.2: What happens on the ERROR/ABORT path?
→ Are there side effects before the error?
→ Does the error message leak sensitive information?
→ Can an attacker cause targeted errors (griefing / DoS)?
→ In languages with exceptions: is cleanup code (finally/defer/
Drop) correct? Are resources leaked on the error path?
Q6.3: What if an EXTERNAL CALL in this function fails silently?
→ Does the language/runtime guarantee failure propagation?
→ Is the error checked, or can it be swallowed?
→ Language examples:
Solidity: low-level call returns (bool, bytes) — often unchecked
Go: err is a normal return value — easy to ignore with _
Rust: .unwrap() can panic; ? propagates but hides the error
C++: exception might be caught too broadly
Move: abort is always propagated (safer by design)
Q6.4: Is there a code path where NO return and NO error happens?
→ Functions falling through without explicit return
→ Default/zero values used when they shouldn't be
→ Missing match/switch arms or else branches
→ Language-specific:
Rust: compiler catches this. Go/C++: does not always.
Solidity: functions can fall through returning zero values.
Category 7: External Call Reordering & Multi-Transaction State Analysis
This category catches bugs that live in the TIMING and SEQUENCING of operations — both within a single transaction and across multiple transactions over time.
Part A: External Call Reordering (within a single transaction)
Q7.1: If the function performs an external call BEFORE a state update,
what happens if I SWAP them — state update first, external call second?
→ If the swap causes a revert: the ORIGINAL ordering may be exploitable
(the external call might re-enter or manipulate state before it's updated)
→ If the swap works cleanly: the original ordering is likely safe,
OR the swap reveals the intended safe ordering was never enforced
→ KEY: Try both directions. The one that reverts tells you which
ordering the code DEPENDS on. The one that doesn't revert tells you
which ordering an attacker can expl
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [grantkee](https://github.com/grantkee)
- **Source:** [grantkee/claude-extensions](https://github.com/grantkee/claude-extensions)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.