Skip to main content
Glama

analyze_psbt_security

Detect mempool sniping vulnerabilities in Bitcoin PSBTs by analyzing signature hash flags and multisig configurations to identify front-running risks in ordinals listings.

Instructions

Analyze a PSBT for ordinals inscription listing mempool sniping vulnerability.

Detects whether an ordinals listing PSBT is vulnerable to front-running in the mempool. A listing is VULNERABLE when it uses SIGHASH_SINGLE|ANYONECANPAY without a 2-of-2 multisig locking step — an attacker can redirect the inscription before confirmation. A listing is PROTECTED when the inscription is locked in a 2-of-2 P2WSH multisig and the marketplace co-signs with SIGHASH_ALL, preventing any transaction modification.

No Bitcoin node required — analysis is pure PSBT parsing (BIP 174).

Args: psbt_hex: Hex-encoded PSBT string (BIP 174 v0)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
psbt_hexYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The tool handler for "analyze_psbt_security" which calls _psbt_analyze to assess the PSBT vulnerability.
    @mcp.tool()
    def analyze_psbt_security(psbt_hex: str) -> str:
        """Analyze a PSBT for ordinals inscription listing mempool sniping vulnerability.
    
        Detects whether an ordinals listing PSBT is vulnerable to front-running in the mempool.
        A listing is VULNERABLE when it uses SIGHASH_SINGLE|ANYONECANPAY without a 2-of-2
        multisig locking step — an attacker can redirect the inscription before confirmation.
        A listing is PROTECTED when the inscription is locked in a 2-of-2 P2WSH multisig and
        the marketplace co-signs with SIGHASH_ALL, preventing any transaction modification.
    
        No Bitcoin node required — analysis is pure PSBT parsing (BIP 174).
    
        Args:
            psbt_hex: Hex-encoded PSBT string (BIP 174 v0)
        """
        result = _psbt_analyze(psbt_hex)
        return json.dumps(result, indent=2)
  • Helper function that parses and analyzes the PSBT for security vulnerabilities.
    def _psbt_analyze(psbt_hex: str) -> dict:
        """Parse a PSBT hex string and return a vulnerability assessment dict."""
        import binascii
    
        try:
            data = binascii.unhexlify(psbt_hex.strip())
        except Exception:
            return {"error": "Invalid hex encoding"}
    
        if not data.startswith(_PSBT_MAGIC):
            return {"error": "Invalid PSBT: missing magic bytes"}
    
        offset = 5
        global_map, offset = _psbt_parse_map(data, offset)
        raw_tx = global_map.get(b"\x00")
        if raw_tx is None:
            return {"error": "Invalid PSBT: missing unsigned transaction (BIP 174 v0 required)"}
    
        input_count, _ = _psbt_read_varint(raw_tx, 4)
        inputs = []
        for i in range(input_count):
            input_map, offset = _psbt_parse_map(data, offset)
    
            sighash_type = None
            if b"\x03" in input_map:
                raw = input_map[b"\x03"]
                sighash_type = int.from_bytes(raw[:4].ljust(4, b"\x00"), "little")
    
            for key, val in input_map.items():
                if key and key[:1] == b"\x02" and len(val) >= 1 and sighash_type is None:
                    sighash_type = val[-1]
    
            sighash_name = _PSBT_SIGHASH_NAMES.get(sighash_type, f"0x{sighash_type:02x}") if sighash_type is not None else None
            witness_script = input_map.get(b"\x05")
            is_multisig = _psbt_is_2of2_multisig(witness_script) if witness_script else False
    
            if sighash_type == 0x83:
                vuln = "protected" if is_multisig else "vulnerable"
            elif sighash_type is not None:
                vuln = "not_applicable"
            else:
                vuln = "unknown"
    
            inputs.append({
                "index": i,
                "sighash_type": sighash_type,
                "sighash_name": sighash_name,
                "has_witness_script": witness_script is not None,
                "is_2of2_multisig": is_multisig,
                "vulnerability": vuln,
            })
    
        vulns = [inp["vulnerability"] for inp in inputs]
        if "vulnerable" in vulns:
            overall_risk = "vulnerable"
        elif "protected" in vulns:
            overall_risk = "protected"
        elif all(v == "not_applicable" for v in vulns):
            overall_risk = "not_inscription_listing"
        else:
            overall_risk = "unknown"
    
        return {"input_count": input_count, "overall_risk": overall_risk, "inputs": inputs}

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Bortlesboat/bitcoin-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server