Skip to content

WSSecurityCert: Security header placed outside Envelope when no other SOAP headers exist #1487

@rubenaguadoc

Description

@rubenaguadoc

Description

When using WSSecurityCert without any other SOAP headers (addSoapHeader), the <wsse:Security> block and <ds:Signature> are placed outside the <soap:Envelope> instead of inside <soap:Header>.

Root Cause

In client.ts, the <soap:Header> element is only created if this.security.toXML() returns a truthy value:

node-soap/src/client.ts

Lines 447 to 458 in 78a71cb

(decodedHeaders || (this.security && this.security.toXML())
? '<' +
envelopeKey +
':Header' +
(this.wsdl.xmlnsInHeader ? ' ' + this.wsdl.xmlnsInHeader : '') +
'>' +
(decodedHeaders ? decodedHeaders : '') +
(this.security && !this.security.postProcess ? this.security.toXML() : '') +
'</' +
envelopeKey +
':Header>'
: '') +

WSSecurityCert does not implement toXML(), so the fallback () => '' is used (line 358):

node-soap/src/client.ts

Lines 409 to 411 in 78a71cb

if (this.security && typeof this.security?.toXML !== 'function') {
this.security.toXML = () => '';
}

Since '' is falsy, the Header element is never created. Then WSSecurityCert.postProcess looks for </${envelopeKey}:Header> to insert the Security block, but it doesn't exist. The indexOf returns -1 and insertStr places the content at the wrong position — outside the Envelope.

Steps to Reproduce

  1. Create a SOAP client with WSSecurityCert as the only security mechanism.
  2. Do NOT call addSoapHeader().
  3. Invoke any SOAP method.
  4. Inspect the raw XML request — the <wsse:Security> block is outside <soap:Envelope>.

Expected Behavior

The <soap:Header> element should always be created when a security mechanism with postProcess is set, so that WSSecurityCert.postProcess can correctly insert the Security block inside it.

Suggested Fix

Either:

  • Have WSSecurityCert implement toXML() returning a truthy placeholder (e.g. ' ') that triggers Header creation, or
  • Change the condition in client.js to also check for the presence of postProcess:
(decodedHeaders || (this.security && (this.security.toXML() || this.security.postProcess))
    ? '<' + envelopeKey + ':Header>...</' + envelopeKey + ':Header>'
    : '')

Workaround

const security = new soap.WSSecurityCert(privatePEM, publicPEM, password, options);
security.toXML = () => ' ';
client.setSecurity(security);

Environment

  • soap version: 1.9.1
  • Node.js version: 22.x
  • OS: Windows

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions