{"id":2767,"library":"signxml","title":"signxml","description":"signxml is a Python library that implements the W3C XML Signature standard (XMLDSig), used for payload security in standards like SAML 2.0, XAdES, EBICS, and WS-Security. It provides features for signing and verifying XML documents, including support for X.509 certificate chains and XAdES signatures. The library is actively maintained with regular releases, supporting modern Python versions (3.9-3.13+).","status":"active","version":"4.4.0","language":"python","source_language":"en","source_url":"https://github.com/XML-Security/signxml","tags":["xml","signature","security","xades","saml","xmlsec"],"install":[{"cmd":"pip install signxml","lang":"bash","label":"Install signxml"}],"dependencies":[{"reason":"Required for XML parsing, manipulation, and canonicalization, offering superior resistance to XML attacks.","package":"lxml","optional":false},{"reason":"Used for core cryptographic operations including certificate parsing, key processing, and signature validation, replacing older PyOpenSSL functionality.","package":"cryptography","optional":false}],"imports":[{"symbol":"XMLSigner","correct":"from signxml import XMLSigner"},{"symbol":"XMLVerifier","correct":"from signxml import XMLVerifier"},{"note":"signxml explicitly uses and requires lxml.etree for robust XML handling and security; standard library ElementTree may lead to parsing and namespace issues.","wrong":"from xml.etree import ElementTree as ET","symbol":"etree","correct":"from lxml import etree"}],"quickstart":{"code":"from lxml import etree\nfrom signxml import XMLSigner, XMLVerifier, SignatureConfiguration\nimport os\n\n# --- Setup: Generate test certificate and key (requires OpenSSL) ---\n# openssl req -x509 -nodes -subj \"/CN=test\" -days 1 -newkey rsa -keyout privkey.pem -out cert.pem\n# In a real application, you would load these from secure storage.\n\n# Ensure cert.pem and privkey.pem exist in the current directory for this example to run.\nif not (os.path.exists('cert.pem') and os.path.exists('privkey.pem')):\n    print(\"Please generate 'cert.pem' and 'privkey.pem' using OpenSSL as described in the comments.\")\n    exit()\n\ncert = open(\"cert.pem\").read()\nkey = open(\"privkey.pem\").read()\n\n# --- Signing an XML document ---\ndata_to_sign = \"<Test><Data>Hello World!</Data></Test>\"\nroot = etree.fromstring(data_to_sign)\n\nsigner = XMLSigner()\nsigned_root = signer.sign(root, key=key, cert=cert)\n\nprint(\"\\n--- Signed XML ---\")\nprint(etree.tostring(signed_root, pretty_print=True).decode())\n\n# --- Verifying the signed XML document ---\nverifier = XMLVerifier()\n\ntry:\n    # It's crucial to explicitly provide the trusted certificate or CA for verification\n    # and to ensure the returned data is what was expected to prevent signature wrapping attacks.\n    verified_data = verifier.verify(signed_root, x509_cert=cert).signed_xml\n    \n    print(\"\\n--- Verification Successful! ---\")\n    print(\"Signed data content:\", etree.tostring(verified_data, pretty_print=False).decode())\n    \n    # Optionally, assert the signature location (best practice for SAML etc.)\n    config = SignatureConfiguration(location='./')\n    verifier.verify(signed_root, x509_cert=cert, expect_config=config)\n    print(\"Signature location asserted successfully.\")\n\nexcept Exception as e:\n    print(f\"\\n--- Verification Failed: {e} ---\")\n","lang":"python","description":"This quickstart demonstrates basic XML signing and verification using `XMLSigner` and `XMLVerifier`. It includes placeholder instructions for generating a test certificate and key using OpenSSL. In production, always load certificates and keys securely and explicitly configure trust for verification. It also highlights the best practice of verifying the `signed_xml` attribute and asserting the signature's expected location."},"warnings":[{"fix":"Update your code to use `cryptography` types and `ca_pem_file` where applicable. Review API documentation for updated methods, especially for certificate chain validation.","message":"Version 4.0.0 introduced a major infrastructure change, replacing PyOpenSSL with Cryptography for core certificate and key handling. The `ca_path` parameter for specifying CA certificate stores was removed and replaced by `ca_pem_file`.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Upgrade to signxml version 4.0.4 or newer immediately to mitigate these vulnerabilities.","message":"Version 4.0.4 contained critical security fixes addressing HMAC algorithm confusion and timing attacks. Running older versions with HMAC-based signatures is highly insecure.","severity":"breaking","affected_versions":"<4.0.4"},{"fix":"Ensure your XML inputs do not contain DTD declarations. If you are processing external XML, sanitize or transform it to remove DTDs before passing it to signxml.","message":"As of version 4.4.0, DTD (Document Type Declaration) declarations are forbidden in XML input for enhanced security, preventing XML External Entity (XXE) attacks.","severity":"breaking","affected_versions":">=4.4.0"},{"fix":"Always import `etree` from `lxml` (`from lxml import etree`) and pass `lxml.etree` objects or raw XML strings directly to signxml. Avoid converting to/from `xml.etree.ElementTree` objects.","message":"signxml relies heavily on `lxml.etree` for its advanced XML parsing, canonicalization, and security features. Using Python's standard `xml.etree.ElementTree` can lead to inconsistent behavior, especially with namespace handling, and may bypass lxml's security protections.","severity":"gotcha","affected_versions":"all"},{"fix":"When verifying, access `result.signed_xml` and incorporate `expect_config=SignatureConfiguration(location='./')` in your `verify()` calls where appropriate.","message":"For robust security, always follow the 'See what is signed' principle. After `XMLVerifier.verify()`, explicitly use the `signed_xml` attribute of the return value, as this is the actual data covered by the signature. Also, for specific standards like SAML, it's a best practice to assert the expected signature location using `SignatureConfiguration(location='./')` to prevent signature wrapping attacks.","severity":"gotcha","affected_versions":"all"},{"fix":"Always specify trust anchors during verification (e.g., `verifier.verify(..., x509_cert=my_trusted_cert)` or `ca_pem_file=\"/path/to/my_ca.pem\")`).","message":"The default `XMLVerifier().verify()` behavior trusts any valid X.509 certificate that validates against your system's CA store. For production, you must explicitly establish trust using parameters like `x509_cert` (a pre-shared certificate), `cert_subject_name` (to validate the subject name in the signing certificate), or `ca_pem_file` (a custom CA bundle) to prevent unauthorized signatures.","severity":"gotcha","affected_versions":"all"},{"fix":"Do not pretty-print or reformat signed XML documents if their signatures are to remain valid.","message":"XML canonicalization, a crucial step in XML Signature, is highly sensitive to whitespace. Pretty-printing an XML document *after* it has been signed will almost certainly invalidate its signature.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"search_vec":"'-3.13':61 '2.0':23 '3.9':60 'activ':51 'certif':43 'chain':44 'document':38 'ebic':25 'featur':32 'implement':8 'includ':39 'librari':6,49 'like':21 'maintain':52 'modern':57 'payload':17 'provid':31 'python':5,58 'regular':54 'releas':55 'saml':22,66 'secur':18,29,64 'sign':34 'signatur':12,47,63 'signxml':1,2 'standard':13,20 'support':40,56 'use':15 'verifi':36 'version':59 'w3c':10 'ws':28 'ws-secur':27 'x.509':42 'xade':24,46,65 'xml':11,37,62 'xmldsig':14 'xmlsec':67","created_at":"2026-04-11T01:41:56.832672+00:00","updated_at":"2026-04-16T21:43:13.576399+00:00","problems":[{"fix":"pip install signxml","cause":"The 'signxml' library has not been installed in the Python environment where the code is being executed.","error":"ModuleNotFoundError: No module named 'signxml'"},{"fix":"Ensure the XML document actually contains a `<ds:Signature>` element and, if necessary, provide the correct `signature_xpath` argument to `XMLVerifier.verify()`.","cause":"The XMLVerifier could not find an XML Signature element (<ds:Signature>) within the provided XML document, often due to an incorrect XPath or the absence of a signature.","error":"signxml.exceptions.InvalidInputError: Unable to locate signature in document"},{"fix":"Verify that the correct public key or certificate is being used, ensure the signed document has not been altered, and confirm that the canonicalization and digest methods match those used during signing.","cause":"The cryptographic verification of the XML signature failed, indicating potential document tampering, an incorrect public key/certificate, or a mismatch in canonicalization or digest algorithms.","error":"signxml.exceptions.SignatureVerificationError: Signature verification failed"},{"fix":"Add a namespace declaration to the root element of your XML document, such as `<root xmlns=\"http://example.com/ns\">`.","cause":"signxml requires the root element of the XML document to have at least one XML namespace declared for proper processing and XPath resolution.","error":"signxml.exceptions.InvalidInputError: Document must contain at least one XMLNS"}],"ecosystem":"pypi","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":"5.1.0","cli_name":"signxml","cli_version":"sh: 1: signxml: not found","type":"library","homepage":null,"github":"https://github.com/XML-Security/signxml","docs":"https://xml-security.github.io/signxml/","changelog":null,"pypi":"https://pypi.org/project/signxml/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["auth-security","serialization"],"base_url":null,"auth_type":null,"provenance":{"verified_status":"passing","verified_at":"2026-06-28","last_verified":"2026-08-28","next_check":"2026-07-28","install_tag":null}}