Instructions to use Neurona/qwen3.8-9b-cyber-exploit-agent with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use Neurona/qwen3.8-9b-cyber-exploit-agent with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M # Run inference directly in the terminal: llama cli -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M # Run inference directly in the terminal: llama cli -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M # Run inference directly in the terminal: ./llama-cli -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M # Run inference directly in the terminal: ./build/bin/llama-cli -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
Use Docker
docker model run hf.co/Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
- LM Studio
- Jan
- Ollama
How to use Neurona/qwen3.8-9b-cyber-exploit-agent with Ollama:
ollama run hf.co/Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
- Unsloth Studio
How to use Neurona/qwen3.8-9b-cyber-exploit-agent with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for Neurona/qwen3.8-9b-cyber-exploit-agent to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for Neurona/qwen3.8-9b-cyber-exploit-agent to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for Neurona/qwen3.8-9b-cyber-exploit-agent to start chatting
- Pi
How to use Neurona/qwen3.8-9b-cyber-exploit-agent with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use Neurona/qwen3.8-9b-cyber-exploit-agent with Docker Model Runner:
docker model run hf.co/Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
- Lemonade
How to use Neurona/qwen3.8-9b-cyber-exploit-agent with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
Run and chat with the model
lemonade run user.qwen3.8-9b-cyber-exploit-agent-Q4_K_M
List all available models
lemonade list
- Hermes Agent
How to use Neurona/qwen3.8-9b-cyber-exploit-agent with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use Neurona/qwen3.8-9b-cyber-exploit-agent with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "Neurona/qwen3.8-9b-cyber-exploit-agent:Q4_K_M" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
| # -*- coding: utf-8 -*- | |
| """Track B part 3: F-gate variety FP family, UNPROVEN/INSUFFICIENT_EVIDENCE honesty set, | |
| absence-hallucination refusal (F19), N13 standalone gate hygiene, xrpl-py Python samples.""" | |
| from trackb_part1 import SYSTEM, PREAMBLE, S, add | |
| # ============================================================ F13 nested batch / standalone inner | |
| F13_USER = """## Report: Nested Batch / standalone tfInnerBatchTxn breaks batch atomicity guarantees | |
| If an inner transaction of a Batch is itself a Batch (nested), or if a single transaction with tfInnerBatchTxn is submitted standalone outside a Batch envelope, the atomicity model of XLS-56 is violated: partial application, replay of inner signatures, or double fee accounting become possible. An attacker can wrap a victim's inner txn in their own Batch context. | |
| Impact: atomicity bypass, signature replay.""" | |
| add("F13", | |
| F13_USER, | |
| """White-Box: Both claimed shapes are rejected at validation, not merely unspecified. | |
| (1) XLS-56 (Batch): nested batches are illegal; Batch preflight/inner validation rejects any inner whose TransactionType is Batch. F13 family. | |
| (2) Standalone tfInnerBatchTxn: the inner-batch flag on a standalone transaction is rejected - inner-only fields are not legal on top-level transactions (temINVALID_FLAG / temBAD_AUTH-style rejection before apply). The standalone server never applies an "inner" transaction outside its parent context. | |
| (3) "Wrapping a victim's inner txn": inner transactions of a Batch carry no standalone signatures (Batch.cpp rejects sfTxnSignature on inners, temBAD_SIGNATURE) and are applied within the parent's view (perTxBatchView) - an attacker cannot lift someone's inner into a foreign context because inners are only meaningful inside their signed parent. | |
| (4) Six-test: test 1 (reachable) fails - both shapes die in preflight/inner-validation; F8-adjacent: the attack is a recombination around a rejected shape. | |
| (5) No code path on develop applies a nested or standalone-inner transaction; verified in Batch inner validation (signature-field rejection, type checks) and STTx level.""", | |
| """Local develop. | |
| 1. Submit Batch with inner TransactionType=Batch -> rejected (inner validation), nothing applied. | |
| 2. Submit standalone tx with tfInnerBatchTxn flag -> rejected at preflight. | |
| 3. Attempt replay: extract an inner JSON, submit standalone -> fails signature/shape validation (inner-only fields illegal standalone). | |
| 4. No partial application observable in any run.""", | |
| """Root cause: none - spec-conformant rejection; the report assumes unvalidated acceptance of illegal shapes. | |
| Reachability: submissions are reachable; application is not. | |
| Primitive: none. | |
| Chain: dead at test 1 (validation). | |
| Missing for VALID: a develop path that ACCEPTS nested/standalone-inner shapes - none exists. | |
| Stability: deterministic. | |
| Fix sketch: none needed; optional: explicit error code distinct from generic temINVALID_FLAG for diagnostics.""", | |
| "FALSE_POSITIVE", "none", | |
| """REASONING: XLS-56 makes nested Batch illegal and inner-only fields (tfInnerBatchTxn, sfTxnSignature) illegal standalone; Batch inner validation (Batch.cpp signature-field rejection, temBAD_SIGNATURE) prevents lifting inners into foreign contexts. Both shapes die at validation - test 1 fails, F13.""") | |
| # ============================================================ F15 sfMPTAmount double subtraction | |
| F15_USER = """## Report: sfMPTAmount accounting bug - available balance double-counts locked amounts | |
| When an MPT holder has locked amounts (e.g. via token escrow/locking features), transaction checks that read sfMPTAmount seem to subtract sfLockedAmount again, even though the locked amount was already decremented when the lock was created. Holders can therefore be wrongly denied payments (funds exist but checks fail), or in the inverse direction attackers can overspend by exploiting the off-by-lock accounting. | |
| Impact: denial of spending / potential overspend.""" | |
| add("F15", | |
| F15_USER, | |
| """White-Box: What does sfMPTAmount mean on the ledger object? | |
| (1) The MPToken ledger object's sfMPTAmount is the AVAILABLE amount: at lock creation the locked portion is already deducted from it (the lock object carries its own sfLockedAmount). Any consumer reading sfMPTAmount therefore sees spendable funds by construction. | |
| (2) A check that additionally subtracts sfLockedAmount from sfMPTAmount would be a genuine bug - but the report names no consumer site doing this (no file:function, no failing transaction type). The claim is "seem to" - speculation without a path. | |
| (3) F15 is the guard against exactly this misreading: sfMPTAmount IS available; do not subtract locks again. | |
| (4) Class decision: no code path cited, no concrete failing tx -> not demonstrably FP as a code matter either; the report as FILED lacks any reconstructable chain. Correct class: UNPROVEN (would need: exact transactor + tx that reads both fields and double-subtracts) - with the F15 prior stated: the schema definition makes the double-subtract shape unlikely, so the burden is a named site. | |
| (5) If a site is later shown subtracting locks from sfMPTAmount: then it would be CORRECTNESS-ISSUE (wrong denial) or VALID (overspend variant) - state exactly what evidence would flip it.""", | |
| """No executable trigger exists yet - the report names no consumer code. What the verification would look like (fetch list): | |
| 1. grep the develop clone for consumers: fields sfMPTAmount AND sfLockedAmount co-occurring in a check (transactors, PermissionedDEXHelpers, escrow/lock helpers). | |
| 2. For each hit: read whether the site subtracts locks from sfMPTAmount (bug shape) or uses sfMPTAmount directly (correct). | |
| 3. Reproduce the claimed denial/overspend with the exact tx on standalone. | |
| Until then: no verdict on the mechanism - UNPROVEN.""", | |
| """Root cause: hypothesized double-subtraction with no cited site; field semantics (sfMPTAmount = available, locks already deducted at lock time) make the shape a schema-misreading candidate (F15 prior). | |
| Reachability: unknown - no path named. | |
| Primitive: none shown. | |
| Chain: not reconstructable from the report. | |
| Missing to next rung: a named consumer site reading both fields + a concrete failing tx - exactly the two fetchables listed in TRIGGER. | |
| Stability: n/a. | |
| Fix sketch: n/a until a site is named; if confirmed, the fix is local (remove the redundant subtraction), the class depends on direction (denial -> correctness; overspend -> ledger-validity candidate).""", | |
| "UNPROVEN", "none", | |
| """REASONING: no consumer site cited, no failing transaction; sfMPTAmount semantics (available, locks deducted at lock creation) contradict the hypothesized shape (F15 prior). Chain not reconstructable: UNPROVEN with explicit fetch list (grep sites reading sfMPTAmount + sfLockedAmount; concrete tx).""") | |
| # ============================================================ F16 CanTrade clear | |
| F16_USER = """## Report: Offers survive lsfMPTCanTrade clear - frozen MPTs remain tradable on the book | |
| The issuer clears lsfMPTCanTrade on an MPT issuance, intending to halt trading. But existing offers on the book are not immediately removed; they keep sitting in the directory. Traders whose offers persist can therefore keep trading a frozen issuance - the freeze is cosmetic until each offer is individually canceled. Attack: place offers, wait for freeze, execute against stale counterparties. | |
| Impact: freeze bypass.""" | |
| add("F16", | |
| F16_USER, | |
| """White-Box: Persistence vs executability again - with a specified eviction moment. | |
| (1) XLS-82 section 9.2: when lsfMPTCanTrade / lsfMPTCanTransfer is cleared, existing offers fall out at the next crossing event (the matcher evicts offers no longer authorized as it walks the book). The book directory may retain entries until touched - specified behavior. | |
| (2) Execution attempt: a cross against a stale offer triggers the authorization check at match time; the stale offer is skipped/evicted, not executed. "Execute against stale counterparties" therefore cannot occur - the counterparty's offer is exactly the thing that gets evicted on touch. | |
| (3) The freeze's purpose (halt new trading) is enforced at the only place trading happens: the match. Persistence of an inert entry harms nobody; the issuer can also sweep via standard offer-cancellation economics if desired. | |
| (4) Six-test: test 5 (live-recheck) kills - match-time authorization re-check (CanTrade-at-cross family, XLS-82 9.2). F16 gate. | |
| (5) F9-adjacent: stale SLE is only a bug if usable WITHOUT re-auth - here use IS re-auth at match.""", | |
| """Local develop. | |
| 1. Issuer creates MPT issuance (canTrade), trader places offer, issuer clears lsfMPTCanTrade. | |
| 2. Observe: offer entry persists in book directory (as reported). | |
| 3. Attempt any cross against it -> matcher re-checks authorization at match, evicts the offer, no execution. | |
| 4. Net tradable volume of the frozen issuance: zero at every match attempt.""", | |
| """Root cause: none - specified lazy eviction (XLS-82 9.2): entries persist, executability dies at the next cross. | |
| Reachability: the persistent entry is reachable/visible; the claimed execution is not. | |
| Primitive: none (no unauthorized trade possible). | |
| Chain: killed at test 5 (match-time re-check). | |
| Missing for VALID: a match path that executes an offer without the CanTrade re-check - none on develop. | |
| Stability: deterministic; amendment-gated fix family may adjust eviction timing but not the re-check itself. | |
| Fix sketch: none required; optional UX: book_offers could annotate evict-pending entries.""", | |
| "FALSE_POSITIVE", "none", | |
| """REASONING: XLS-82 section 92: cleared lsfMPTCanTrade evicts offers at the next cross (match-time re-check); persistence of the entry without executability is specified lazy cleanup. Test 5 kills the chain (F16, F9).""") | |
| # ============================================================ F17 Supported::No standalone | |
| F17_USER = """## Report: Force-enabling unsupported features on standalone breaks consensus-relevant validation | |
| By running rippled in standalone with [features] config overrides, I force-enabled an amendment that is Supported::No on develop. The node accepts transactions using that feature and applies them. This means validators could also be tricked into enabling it, and the feature's transactor has security holes (it was disabled for a reason). | |
| Impact: consensus split / security holes in unreleased code.""" | |
| add("F17", | |
| F17_USER, | |
| """White-Box: Conflate-free reading of what force-enable on standalone proves. | |
| (1) Standalone mode exists precisely for testing unsupported/unreleased features; config feature overrides on a non-validating, non-consensus node are operator-self choices. Supported::No on develop marks not-ready-for-mainnet, not "contains known holes". | |
| (2) "Validators could be tricked into enabling it": amendment activation on a live network requires the documented voting/supermajority process across validators - an operator's standalone config proves nothing about that path and no trick is described. Without a described activation attack, the consensus claim is speculation. | |
| (3) The "transactor has security holes" claim: unnamed holes, no path - pure inference from its disabled status. | |
| (4) F17: force-enable on standalone is not a mainnet-critical finding. What COULD be real (honest boundary): (a) a specific reachable bug IN the disabled transactor that ALSO manifests once enabled properly - file THAT bug against the transactor code directly (it stays valid regardless of enablement state); (b) an amendment-activation attack - would need its own mechanism writeup. Neither is in this report. | |
| (5) Class: the report as filed generalizes from a standalone config to network compromise - premise leap. FALSE_POSITIVE (with the boundary stated).""", | |
| """Local standalone node. | |
| 1. Force-enable the Supported::No feature via config in standalone -> node applies its transactions (as designed for testing). | |
| 2. Attempt the leap: no validator in any network follows the standalone node's config; amendment state on other nodes unchanged (observe: nothing to observe - the claim has no network-side trigger). | |
| 3. The claimed security holes: none demonstrated - pick any concrete crash/bypass in the transactor and file THAT with a repro; it would be judged on its own merits regardless of Supported::No.""", | |
| """Root cause: category error - standalone test behavior read as network attack surface. | |
| Reachability: the network-side claim (validator trick) has no described trigger path; standalone acceptance is by design. | |
| Primitive: none. | |
| Chain: no rung exists toward consensus impact. | |
| Missing for VALID: either a concrete transactor bug (filed against the code, not the enablement) or a concrete amendment-activation attack. | |
| Stability: n/a. | |
| Fix sketch: n/a; engineering hygiene note - unreleased transactors keep evolving; security review belongs on the code, not the flag.""", | |
| "FALSE_POSITIVE", "none", | |
| """REASONING: standalone force-enable is operator-local test behavior (F17); no mechanism from a local config override to network-wide activation is described; "disabled = insecure" is inference without a path. Consensus/holes claims unsupported.""") | |
| # ============================================================ F19 absence hallucination refusal | |
| F19_USER = """## Report: ConfidentialMPTSend doesn't exist in rippled - confidential balance can be spent by anyone via the raw MPT path | |
| I looked at the code and there is no ConfidentialMPTSend transactor - the confidential amounts are just bytes on the MPToken object. Anyone holding the MPT can spend the "confidential" balance through the normal Payment/MPTokenAuthorize path because there is no confidential-specific validation anywhere. The confidential feature is vaporware and the balances are unprotected. | |
| Impact: complete bypass of confidential transfer controls.""" | |
| add("F19", | |
| F19_USER, | |
| """White-Box: The premise is a false absence claim - verify before reasoning. | |
| (1) The transactor EXISTS on develop: src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp (plus ConfidentialMPTConvert, ConfidentialMPTConvertBack, ConfidentialMPTMergeInbox, ConfidentialMPTClawback in the same directory; ConfidentialTransfer amendment family with ConfidentialMPTSend.cpp gated checks: lsfMPTCanTransfer, lsfMPTCanHoldConfidentialBalance, issuer ElGamal key, auditor ciphertext rules, transfer-fee sanity at ConfidentialMPTSend.cpp:196-199). | |
| (2) The claim "no confidential-specific validation anywhere" is refuted by the file's preclaim/doApply gate set - confidential spends are their own validated path, not the open Payment path. | |
| (3) "Anyone can spend confidential balance via Payment/MPTokenAuthorize": the confidential balance is a separate encrypted state (inbox/convert objects); the open path operates on sfMPTAmount (available), which the lock/convert moves already deducted - the two domains do not alias. | |
| (4) F19: never claim absence from memory - the report's entire chain hangs on a nonexistent void; refuting the premise kills the chain before any six-test walk. If the reporter read an old branch or a fork, the current-develop check is the resolution step. | |
| (5) Honesty clause: if some third party DID demonstrate spending another account's confidential state via the open path, that would be critical - nothing of the sort is shown; the shown mechanism is an absence claim.""", | |
| """Develop clone, one command: ls src/libxrpl/tx/transactors/token/ -> ConfidentialMPTSend.cpp (+Convert/ConvertBack/MergeInbox/Clawback). Read preclaim/doApply: the gate set (transfer flag, confidential-hold flag, issuer key, auditor rules, fee sanity) exists precisely where the report claims "no validation anywhere". The open-path aliasing claim dies on field semantics: sfMPTAmount excludes converted (locked) amounts.""", | |
| """Root cause: false absence premise (feature exists with its own validated transactor path); secondary aliasing claim contradicted by the balance-domain split (available vs converted confidential state). | |
| Reachability: the claimed unprotected spend has no path - the confidential state is only movable through its own gated transactors. | |
| Primitive: none. | |
| Chain: dead at premise (F19). Missing for VALID: an actual open-path tx that moves another party's confidential balance - none shown or constructible. | |
| Stability: n/a. | |
| Fix sketch: none; process note - absence claims require reading the current develop tree first.""", | |
| "FALSE_POSITIVE", "none", | |
| """REASONING: premise refuted on current develop - ConfidentialMPTSend.cpp exists with full preclaim/doApply validation (incl. ConfidentialMPTSend.cpp:196-199); confidential balance is a separate state domain the open path cannot touch. F19: absence claims die on source check.""") | |
| # ============================================================ F20 same residual refile | |
| F20_USER = """## Report: Sponsored Batch reserve manipulation (new filing) | |
| Sponsored Batch transactions with spfSponsorReserve on the outer transaction desync the sponsor's owner-count accounting when inner transactions create objects and a later inner fails under tfUntilFailure. New evidence: I combined it with Permission Delegation this time, which changes the trust boundary. | |
| Impact: sponsor reserve corruption.""" | |
| add("F20", | |
| F20_USER, | |
| """White-Box: Recognize the residual signature. | |
| (1) The core claim is the sponsored-Batch reserve-desync residual: outer Batch + spfSponsorReserve + object-creating inners + late failure. That shape dies in Batch::preflight (Batch.cpp:220-228, temINVALID_FLAG) - F1. Identical residual to previously closed reports. | |
| (2) "New differential": adding Permission Delegation changes the submitter identity, not the validation path - Batch preflight runs identically regardless of who submits (delegate or principal). The claimed trust-boundary change does not reach the gate. | |
| (3) F20: same residual + no new differential -> same verdict. The remix-with-delegation was already the closed combination's own shape (F8 covers recombination; F20 covers re-filing). | |
| (4) A NEW differential would look like: a different field combination that BYPASSES Batch.cpp:220-228 (e.g. a sponsor shape preflight accepts), or object creation without Batch accounting. Not present. | |
| (5) Six-test: test 1 unreachable (tem kill).""", | |
| """Local develop: submit the delegated sponsored Batch (outer spfSponsorReserve) -> temINVALID_FLAG from Batch::preflight, identical to the non-delegated variant. Diff the two results: byte-identical rejection. The "trust boundary" input changes nothing observable.""", | |
| """Root cause: re-file of a known-dead residual with a cosmetic differential (submitter identity). | |
| Reachability: submission reachable; application not (F1 gate). | |
| Primitive: none. | |
| Chain: dead at test 1; F20 (same residual, no new differential). | |
| Missing for VALID: a sponsor shape that survives Batch::preflight - none identified. | |
| Stability: deterministic. | |
| Fix sketch: none.""", | |
| "FALSE_POSITIVE", "none", | |
| """REASONING: identical residual to the closed sponsored-Batch reports (outer spfSponsorReserve -> temINVALID_FLAG, Batch.cpp:220-228, F1); delegation only changes the submitter, not the validation path - no new differential (F20, F8).""") | |
| # ============================================================ N13 standalone sign verify skip | |
| N13_USER = """## Report: TransactionSign skips signature-source validation in standalone mode - forgeable signatures | |
| In TransactionSign, the check `verify && !config.standalone() && validatedLedgerAge > kMaxValidatedLedgerAge` means in standalone mode the validated-ledger-age validation is skipped entirely. A standalone node will happily sign transactions with stale/unvalidated ledger context. Attackers running standalone nodes can therefore produce signatures that honest nodes might accept - signature forgery by mode confusion. | |
| Impact: signature forgery.""" | |
| add("N13", | |
| N13_USER, | |
| """White-Box: What does the standalone clause actually gate? | |
| (1) TransactionSign.cpp:385: the clause combines "not standalone" with ledger-age freshness - the skipped check is a CONTEXT-FRESHNESS precondition for signing (am I signing against a reasonably recent validated ledger?), not a signature-cryptographic check. Signatures produced are always cryptographically valid keysignatures over the exact tx bytes. | |
| (2) Who runs the "vulnerable" node? The operator who chose standalone mode - a local development mode with no network. The "attacker" signing on their own standalone node is signing with their own key material; nothing about another party's security is touched. | |
| (3) "Honest nodes might accept": any node accepting a tx validates its signature against the tx bytes and account state - a signature from a standalone node is just a signature; there is no mode flag carried or trusted. No forgery mechanism exists. | |
| (4) N13 assessment: the fail-open condition (standalone) exists, but D2 asks whether the protection circle is occupied on DEFAULT nodes - standalone is not a default-node circumstance; the check stays fully live on every networked node. Circumstance fail-open on a dev-only mode = hygiene at most. | |
| (5) Class: HYGIENE, severity none. The real-world reading: standalone is exempt from freshness gating because it has no network freshness by definition.""", | |
| """Owned standalone node: submit sign RPC with old ledger index -> signature produced (context-freshness skipped by design). Submit that signed tx to any networked node -> normal signature/account validation applies (no acceptance shortcut, no forgery). The "attack" node is one the attacker already owns with keys they already hold.""", | |
| """Root cause: none - mode-scoped precondition (context freshness requires a network); the skipped check is not a cryptographic validation. | |
| Reachability: standalone-only; default nodes unaffected (D2). | |
| Primitive: none (no forgery path - downstream nodes never trust producer mode). | |
| Chain: no rung toward third-party harm. | |
| Missing for VALID: a mechanism where node mode leaks into acceptance semantics elsewhere - none. | |
| Stability: deterministic. | |
| Fix sketch: optional clarity - assert/log the standalone exemption at the check site to preempt misreadings.""", | |
| "HYGIENE", "none", | |
| """REASONING: TransactionSign.cpp:385 skips a ledger-context-freshness precondition (not signature validation) only in standalone dev mode (N13 fail-open with D2=no: default nodes keep the check); downstream nodes validate signatures independently of producer mode - no forgery mechanism.""") | |
| # ============================================================ UNPROVEN: novel mechanism without source | |
| UNP1_USER = """## Report: Hybrid offer additional-books desync lets offers trade on wrong domain books | |
| Hybrid offers (sfDomainID + sfAdditionalBooks) might race the domain re-check when multiple domain books are involved: the matcher could consume the offer on one book while the credential for the other book is stale, because the re-check happens per-stream, not per-book-set. I have not read OfferStream closely, but the shape suggests a window where the offer is evicted from one book but still consumed from another. | |
| Impact: cross-domain permission bypass on the MPT DEX.""" | |
| add("UNP1", | |
| UNP1_USER, | |
| """White-Box: The report itself flags the gap: "have not read OfferStream closely". | |
| (1) What is known from code already read: OfferStream (OfferStream.cpp:260-274) re-checks offers with sfDomainID against the live view via offerInDomain when walking a book; fixCleanup3_3_0 scopes the check to domain books while hybrid offers also participate in the open book. | |
| (2) The NEW claim - per-book-set desync across sfAdditionalBooks streams - would require reading: how each stream (open book vs domain books vs additional books) constructs its OfferStream, whether eviction (permRmOffer) is keyed to the OFFER (ledger entry key) rather than the book (so eviction in one stream kills the entry for all), and whether consumption is atomic across streams within one tx. | |
| (3) permRmOffer(entry->key()) operates on the offer entry, not a book-local shadow - if that holds everywhere, the "evicted here but consumed there" window cannot exist. But I will not assert this as verified for every additional-books path without reading those construction sites. | |
| (4) Honesty rule 3: no verdict from memory on an unread path. UNPROVEN with the exact fetch list; note the prior: the entry-keyed eviction shape makes the desync unlikely, same family as F3/F9/F16 kills. | |
| (5) What evidence would flip it: a repro where an offer executes a cross on a book whose domain credential was revoked between streams - that would be test 5 failing for real (VALID candidate).""", | |
| """No executable trigger yet - the window is asserted, not shown. Verification plan (fetch list): | |
| 1. Read all OfferStream construction sites for hybrid/additional books (which view, which domain parameter each stream passes). | |
| 2. Confirm permRmOffer keying: entry-key eviction (shared across streams) vs book-local removal. | |
| 3. Check cross-stream consumption atomicity within one Payment apply. | |
| 4. If a window survives reading: construct standalone repro (revoke credential mid-path cannot happen mid-tx; the realistic shape is two txs racing eviction - evaluate whether tx atomicity already kills it). | |
| Only then does a trigger exist; until then the chain is not reconstructable.""", | |
| """Root cause: hypothesized per-stream re-check desync on multi-book hybrid offers; current evidence = code already read shows entry-keyed eviction (unfavorable to the hypothesis), but additional-books stream construction unread. | |
| Reachability: unknown (depends on unread construction sites). | |
| Primitive: none shown. | |
| Chain: not reconstructable from the report - it self-declares non-reading. | |
| Missing to next rung: steps 1-4 in TRIGGER - all readable from the develop clone; a repro script if a window survives. | |
| Stability: if real, would be race/timing-sensitive - factor into any future verdict. | |
| Fix sketch: n/a pre-verification.""", | |
| "UNPROVEN", "none", | |
| """REASONING: mechanism asserted without source reading (self-declared); known code (entry-keyed permRmOffer, OfferStream.cpp:255-274) argues against the window but additional-books construction sites unread - no verdict from memory. Fetch list: OfferStream construction per book type, eviction keying, cross-stream atomicity, then repro-or-close.""") | |
| # ============================================================ INSUFFICIENT_EVIDENCE: no close reason, no repro | |
| IE1_USER = """## Report: AccountDelete left artifacts that still pay out | |
| Someone deleted an account and afterwards some artifact of it still paid out funds in a way I cannot fully reconstruct. I saw the account delete in the ledger, then later a payment from something related. I don't have the tx hashes anymore and it was on a fork of the code with custom patches. | |
| Classify this.""" | |
| add("IE1", | |
| IE1_USER, | |
| """White-Box: What would judging this require, and what is present? | |
| (1) Present: a narrative - deletion observed, later payment "from something related", no hashes, custom-patched fork. | |
| (2) Absent: transaction hashes/indices, ledger versions, the patch set, the artifact type, the actual payment path. Without hashes there is nothing to check against a ledger; on a custom fork, upstream develop verdicts do not transfer. | |
| (3) Why not UNPROVEN? UNPROVEN = mechanism stated, chain reconstructable in principle, verification pending (fetchable). Here even the mechanism is unspecified ("something related") - there is no chain to verify. The honest class is INSUFFICIENT_EVIDENCE. | |
| (4) Known related class (for context, not a verdict): deleted-account artifacts are a guarded invariant family on develop (deleted-account-artifacts invariant work); but mapping this report to that family would be guessing. | |
| (5) What flips it: hashes + repro on unpatched develop (then standard six-test), or the patch set (then it is a fork bug, judged on the fork).""", | |
| """No trigger constructable: no hashes, no artifact type, custom fork. The request that WOULD make it actionable: (a) tx hashes/ledger index of delete + payment, (b) the payment's actual path (regular key? escrow finish? check cash? signer list remnant?), (c) whether the fork patches touch account-delete or payment paths. With those, standalone repro on develop decides.""", | |
| """Root cause: unknown - report does not specify a mechanism. | |
| Reachability: unknown. | |
| Primitive: none identified. | |
| Chain: not stated - INSUFFICIENT_EVIDENCE is the verdict BECAUSE no chain exists to test (distinct from UNPROVEN's verifiable-pending chain). | |
| Missing to next rung: the three fetchables in TRIGGER. | |
| Stability: n/a. | |
| Fix sketch: n/a.""", | |
| "INSUFFICIENT_EVIDENCE", "none", | |
| """REASONING: no hashes, no mechanism, custom-patched fork - nothing reconstructable to test (weaker than UNPROVEN: no chain even hypothesized precisely). Required before any verdict: tx hashes, payment path, patch set.""") | |
| # ============================================================ xrpl-py: partial payment / DeliverMax claim | |
| PY1_USER = """## Report (xrpl-py): send_payment does not set DeliverMax, so receivers can be short-paid andaml parsers misread amounts - funds at risk | |
| In xrpl-py, Wallet.send_payment (or the equivalent helper) builds the Payment without DeliverMax / tfPartialPayment handling, so malicious senders can short-pay receivers (partial payment attack) and the library's amount parsing trusts the delivered amount instead of the delivered_amount metadata. Any wallet built on this loses money. | |
| Impact: user fund loss via partial payments.""" | |
| add("PY1", | |
| PY1_USER, | |
| """White-Box: Split the claim into library behavior vs protocol semantics. | |
| (1) Protocol: partial payment risk is a RECEIVER-side parsing discipline (read delivered_amount from metadata, not the Amount field; enable tfPartialPayment awareness). Any client that books transfers from the Amount field is vulnerable REGARDLESS of library - this is the documented partial-payment vector, old and public. | |
| (2) Library claims - two concrete sub-claims: (a) send_payment omits DeliverMax: DeliverMax is the field that CAPS the deliverable when partial payment is allowed; modern xrpl-py response/payment models handle amounts per current spec (Request model builds Payment fields explicitly; response parsing exposes delivered_amount where present). (b) "parsers trust Amount": xrpl-py response objects expose both the requested amount and metadata-derived delivered values; thebooking decision is application code. | |
| (3) No file:function, no version, no PoC line in the report - and the claim pattern ("any wallet loses money") is the generic partial-payment advisory shape, older than the library's current models. | |
| (4) Honest boundary: IF a specific xrpl-py version's response model dropped delivered_amount or a helper silently booked Amount, that would be a real library correctness/security bug - needs the version + method. Without it: the report as filed generalizes a protocol discipline issue onto an unnamed library behavior. | |
| (5) Class: UNPROVEN pending the two named artifacts (version + response model behavior); the protocol-side advisory part is documented behavior, not a bug.""", | |
| """No trigger against named code yet. Fetch list: | |
| 1. xrpl-py version + exact call path (which model: PaymentRequest fields; which response field read). | |
| 2. Show a concrete Payment built by the lib on a partial-payment execution: does the response expose delivered_amount and does the lib surface it? | |
| 3. If a helper books Amount silently: that line is the repro (library bug); if the lib surfaces both and the app chose wrong: protocol-discipline advisory, not a lib bug. | |
| A PoC would be: lib version X, call send_payment-shaped helper, partial-funded sender, observe lib-reported delivered value vs metadata delivered_amount.""", | |
| """Root cause: partially protocol-discipline (receiver must read delivered_amount - documented), partially an unverified library claim (no version/method cited). | |
| Reachability: the partial-payment vector is real and reachable on any XRPL client that misbooks; the LIBRARY-side defect is unverified. | |
| Primitive: economic (short-pay) IF a lib surface hides delivered data - unshown. | |
| Chain: complete only on the protocol-discipline side (advisory); library side lacks the one cited line. | |
| Missing to next rung: version + exact response-model behavior (the two fetchables). | |
| Stability: deterministic if shown. | |
| Fix sketch: application-side (book from delivered_amount); library-side only if the fetch list reveals a hiding surface.""", | |
| "UNPROVEN", "none", | |
| """REASONING: protocol half is documented receiver discipline (delivered_amount, not Amount), not a library bug; library half cites no version/method/line - unverified surface. UNPROVEN pending version + response-model evidence; flip condition stated.""") | |
| # ============================================================ xrpl-py: tfSell semantics claim | |
| PY2_USER = """## Report (xrpl-py / OfferCreate): tfSell flag lets the matcher steal the spread - sell offers overpay fees | |
| When submitting OfferCreate with tfSell (Sell as much as needed), the taker gets extra value because the offer crosses worse than the limit - the matcher converts the remaining into a fee-like spread capture for counterparties. Using the library's default flags, users lose the difference. This is an off-by-flags funds leak. | |
| Impact: spread theft from retail offers.""" | |
| add("PY2", | |
| PY2_USER, | |
| """White-Box: tfSell semantics against the claim. | |
| (1) tfSell (and its buy-side counterpart) specifies EXECUTION STRATEGY, not a bonus to anyone: tfSell = "sell the full specified TakerGets amount, accept whatever TakerPays the book gives (up to limit)". The "worse than the limit" reading inverts the meaning - the limit remains enforced; what changes is which side's quantity is guaranteed. | |
| (2) The spread goes to the COUNTERPARTIES whose resting offers are consumed at their own quoted prices - standard AMM/orderbook economics, identical on every DEX. No rule is broken and no extra fee exists: fees are the standard offer transaction fee + transfer fees if the issuer set them. | |
| (3) Library angle: flag defaults are explicit in the request models; a user setting tfSell accepts its documented strategy. There is no secret conversion of "remaining into fee-like capture" - unsold remainder simply becomes a resting offer (unless ImmediateOrKill/limit shapes say otherwise). | |
| (4) Six-test/ledger framing: no state deviation from any spec/XLS - test 4 (not-by-design) fails in the strongest form: this IS the design. | |
| (5) Educational-value note for the verdict: reports in this family should be resolved by quoting the flag semantics and the limit-enforcement, then declining the security claim.""", | |
| """Explorer-level, any library or raw tx. | |
| 1. Submit tfSell offer into a book with a known spread; observe fills at resting offers' prices within the stated limit; unsold remainder rests as an offer. | |
| 2. Compare with non-tfSell: fills stop at the quantity condition instead - the LIMIT is enforced in both. | |
| 3. Compute counterparty gains: exactly their quoted spread, available to anyone posting resting offers - no leak beyond market economics.""", | |
| """Root cause: none - documented flag semantics misread as a leak. | |
| Reachability: the behavior is reachable and specified. | |
| Primitive: none (no deviation). | |
| Chain: no rung; test 4 fails (by-design). | |
| Missing for VALID: a fill OUTSIDE the stated limit or a fee not in the fee schedule - neither occurs. | |
| Stability: deterministic. | |
| Fix sketch: none; optional library-side: documentation emphasis on strategy flags for retail integrators.""", | |
| "FALSE_POSITIVE", "none", | |
| """REASONING: tfSell is a documented execution-strategy flag (quantity-guaranteed sell within enforced limits); spread captured by resting counterparties at their own quoted prices is market economics, not a rule break - by-design (test 4).""") | |
| # ============================================================ HYGIENE: misleading log line | |
| HY1_USER = """## Report: Misleading shard log message during catch-up misleads operators about validation state | |
| During ledger catch-up the node logs "Fully validated" for shards that are only acquired, not validated. Operators (me) waited on that line before trusting the node. The wording overstates validation completeness; a later replay found the shard was not fully validated at log time. | |
| Impact: operator confusion; delayed incident response.""" | |
| add("HY1", | |
| HY1_USER, | |
| """White-Box: Class discipline for logging-shape findings. | |
| (1) Is the drift real? Assuming the wording mismatch as described (log claims validated at acquire-time): the code-vs-log contract deviates - real drift, worth fixing. | |
| (2) Does a security boundary depend on it? Logs are operator surfaces, not protocol inputs: no node decision reads that log line; validation itself proceeds by its own state machine regardless of wording. F11 family: logging/docs shape is not protocol security. | |
| (3) E-splitter/D-splitter n/a (no protection circumvented). The harm is human-factor (delayed operator response) - operational hygiene. | |
| (4) Class: HYGIENE, severity none (per class rules: never LOW - hygiene severity is always none). | |
| (5) Boundary honesty: if a MONITORING/ALARM integration gates on that exact line and auto-trusts the node, the deployment converted a wording bug into an availability decision - still fixed by the same log correction; class unchanged.""", | |
| """Owned node in catch-up: reproduce the log sequence (acquire shard -> observe "Fully validated"-style line -> complete validation later); diff log timestamp vs validation-complete state machine transition. The mismatch window is the demonstrable drift.""", | |
| """Root cause: log message wording claims a validation state earlier than the state machine reaches it. | |
| Reachability: every catch-up; deterministic. | |
| Primitive: none (operator-surface drift only). | |
| Chain: no protocol rung; impact bounded to human/monitoring confusion. | |
| Missing for VALID: a protocol or auth decision consuming that line - none exists. | |
| Stability: deterministic. | |
| Fix sketch: split the log states (acquired vs validated) with distinct messages; add a test asserting the validated-log only emits at the validated transition.""", | |
| "HYGIENE", "none", | |
| """REASONING: real contract drift in an operator log (F11 domain: not protocol security); no node decision consumes the line; harm is human-factor. HYGIENE, severity none (never LOW).""") | |