@blamejs/core 0.15.12 → 0.15.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/index.js +2 -0
- package/lib/a2a-tasks.js +45 -29
- package/lib/acme.js +6 -5
- package/lib/agent-event-bus.js +18 -4
- package/lib/agent-idempotency.js +7 -6
- package/lib/agent-orchestrator.js +2 -5
- package/lib/agent-saga.js +3 -5
- package/lib/agent-snapshot.js +32 -2
- package/lib/agent-tenant.js +2 -5
- package/lib/ai-adverse-decision.js +2 -15
- package/lib/ai-aedt-bias-audit.js +2 -1
- package/lib/ai-capability.js +1 -6
- package/lib/ai-content-detect.js +1 -3
- package/lib/ai-dp.js +1 -5
- package/lib/ai-frontier-protocol.js +1 -1
- package/lib/ai-input.js +2 -2
- package/lib/ai-model-manifest.js +1 -1
- package/lib/ai-output.js +16 -7
- package/lib/ai-pref.js +3 -8
- package/lib/ai-quota.js +3 -14
- package/lib/api-key.js +37 -28
- package/lib/api-snapshot.js +4 -1
- package/lib/app-shutdown.js +7 -1
- package/lib/archive-adapters.js +2 -4
- package/lib/archive-entry-policy.js +32 -0
- package/lib/archive-gz.js +9 -0
- package/lib/archive-read.js +14 -24
- package/lib/archive-tar-read.js +56 -24
- package/lib/archive.js +6 -12
- package/lib/arg-parser.js +7 -6
- package/lib/asn1-der.js +70 -22
- package/lib/asyncapi-traits.js +2 -6
- package/lib/atomic-file.js +312 -33
- package/lib/audit-chain.js +183 -54
- package/lib/audit-daily-review.js +36 -16
- package/lib/audit-emit.js +82 -0
- package/lib/audit-sign.js +258 -0
- package/lib/audit-tools.js +108 -23
- package/lib/audit.js +91 -2
- package/lib/auth/access-lock.js +7 -29
- package/lib/auth/bot-challenge.js +1 -1
- package/lib/auth/ciba.js +43 -4
- package/lib/auth/dpop.js +29 -36
- package/lib/auth/fido-mds3.js +14 -16
- package/lib/auth/jwt-external.js +26 -8
- package/lib/auth/jwt.js +15 -17
- package/lib/auth/lockout.js +24 -27
- package/lib/auth/oauth.js +67 -45
- package/lib/auth/oid4vci.js +55 -32
- package/lib/auth/oid4vp.js +3 -2
- package/lib/auth/openid-federation.js +6 -6
- package/lib/auth/passkey.js +4 -4
- package/lib/auth/password.js +8 -2
- package/lib/auth/saml.js +70 -40
- package/lib/auth/sd-jwt-vc-holder.js +2 -14
- package/lib/auth/sd-jwt-vc-issuer.js +2 -14
- package/lib/auth/sd-jwt-vc.js +25 -5
- package/lib/auth/status-list.js +21 -9
- package/lib/auth/step-up.js +15 -13
- package/lib/auth-bot-challenge.js +27 -39
- package/lib/backup/bundle.js +18 -20
- package/lib/backup/crypto.js +23 -8
- package/lib/backup/index.js +55 -67
- package/lib/backup/manifest.js +7 -1
- package/lib/bounded-map.js +112 -1
- package/lib/breach-deadline.js +1 -11
- package/lib/break-glass.js +41 -22
- package/lib/cache.js +7 -18
- package/lib/cbor.js +36 -12
- package/lib/cdn-cache-control.js +15 -12
- package/lib/cert.js +8 -13
- package/lib/chain-writer.js +162 -47
- package/lib/cli.js +10 -2
- package/lib/client-hints.js +7 -9
- package/lib/cloud-events.js +43 -33
- package/lib/cluster-storage.js +9 -41
- package/lib/cms-codec.js +2 -1
- package/lib/codepoint-class.js +84 -1
- package/lib/compliance-ai-act-logging.js +1 -6
- package/lib/compliance-ai-act-transparency.js +2 -4
- package/lib/compliance-eaa.js +2 -12
- package/lib/compliance-sanctions-fetcher.js +21 -28
- package/lib/compliance-sanctions.js +11 -21
- package/lib/compliance.js +3 -10
- package/lib/config-drift.js +24 -20
- package/lib/content-credentials.js +11 -8
- package/lib/content-digest.js +21 -12
- package/lib/cookies.js +15 -13
- package/lib/cose.js +39 -11
- package/lib/cra-report.js +1 -11
- package/lib/crdt.js +2 -1
- package/lib/crypto-field.js +34 -33
- package/lib/crypto.js +138 -7
- package/lib/csp.js +239 -3
- package/lib/daemon.js +46 -42
- package/lib/data-act.js +46 -13
- package/lib/db-file-lifecycle.js +14 -6
- package/lib/db-query.js +75 -49
- package/lib/db.js +66 -27
- package/lib/dbsc.js +5 -6
- package/lib/ddl-change-control.js +18 -14
- package/lib/deprecate.js +4 -5
- package/lib/did.js +6 -2
- package/lib/dora.js +43 -13
- package/lib/dr-runbook.js +1 -1
- package/lib/dsa.js +2 -1
- package/lib/dsr.js +30 -20
- package/lib/early-hints.js +19 -0
- package/lib/eat.js +5 -1
- package/lib/external-db-migrate.js +21 -22
- package/lib/external-db.js +74 -30
- package/lib/fda-21cfr11.js +42 -13
- package/lib/fdx.js +22 -18
- package/lib/file-upload.js +80 -66
- package/lib/flag-evaluation-context.js +5 -8
- package/lib/flag-providers.js +6 -2
- package/lib/forms.js +1 -1
- package/lib/framework-error.js +12 -0
- package/lib/framework-schema.js +19 -0
- package/lib/fsm.js +7 -12
- package/lib/gate-contract.js +911 -39
- package/lib/gdpr-ropa.js +22 -22
- package/lib/graphql-federation.js +18 -5
- package/lib/guard-agent-registry.js +2 -1
- package/lib/guard-all.js +3 -2
- package/lib/guard-archive.js +9 -30
- package/lib/guard-auth.js +23 -80
- package/lib/guard-cidr.js +20 -96
- package/lib/guard-csv.js +135 -196
- package/lib/guard-domain.js +23 -106
- package/lib/guard-dsn.js +17 -14
- package/lib/guard-email.js +46 -53
- package/lib/guard-envelope.js +2 -2
- package/lib/guard-event-bus-topic.js +2 -1
- package/lib/guard-filename.js +12 -60
- package/lib/guard-graphql.js +28 -75
- package/lib/guard-html-wcag.js +15 -2
- package/lib/guard-html.js +74 -128
- package/lib/guard-idempotency-key.js +2 -1
- package/lib/guard-image.js +280 -77
- package/lib/guard-imap-command.js +9 -10
- package/lib/guard-jmap.js +1 -1
- package/lib/guard-json.js +101 -109
- package/lib/guard-jsonpath.js +20 -88
- package/lib/guard-jwt.js +32 -114
- package/lib/guard-list-id.js +2 -7
- package/lib/guard-list-unsubscribe.js +2 -7
- package/lib/guard-mail-compose.js +5 -6
- package/lib/guard-mail-move.js +3 -2
- package/lib/guard-mail-query.js +5 -3
- package/lib/guard-mail-sieve.js +6 -7
- package/lib/guard-managesieve-command.js +6 -5
- package/lib/guard-markdown.js +76 -110
- package/lib/guard-message-id.js +5 -6
- package/lib/guard-mime.js +20 -99
- package/lib/guard-oauth.js +19 -73
- package/lib/guard-pdf.js +65 -72
- package/lib/guard-pop3-command.js +13 -14
- package/lib/guard-posture-chain.js +2 -1
- package/lib/guard-regex.js +24 -99
- package/lib/guard-saga-config.js +2 -1
- package/lib/guard-shell.js +22 -87
- package/lib/guard-smtp-command.js +9 -12
- package/lib/guard-sql.js +15 -13
- package/lib/guard-stream-args.js +2 -1
- package/lib/guard-svg.js +103 -149
- package/lib/guard-template.js +23 -80
- package/lib/guard-tenant-id.js +2 -1
- package/lib/guard-text.js +592 -0
- package/lib/guard-time.js +27 -95
- package/lib/guard-uuid.js +21 -93
- package/lib/guard-xml.js +76 -106
- package/lib/guard-yaml.js +24 -60
- package/lib/html-balance.js +7 -3
- package/lib/http-client-cache.js +5 -12
- package/lib/http-client-cookie-jar.js +35 -16
- package/lib/http-client.js +233 -74
- package/lib/http-message-signature.js +3 -2
- package/lib/i18n-messageformat.js +5 -7
- package/lib/i18n.js +83 -26
- package/lib/iab-tcf.js +3 -2
- package/lib/importmap-integrity.js +41 -1
- package/lib/inbox.js +8 -8
- package/lib/incident-report.js +12 -27
- package/lib/ip-utils.js +49 -6
- package/lib/jobs.js +3 -2
- package/lib/json-patch.js +1 -1
- package/lib/json-path.js +24 -3
- package/lib/jtd.js +2 -2
- package/lib/keychain.js +6 -18
- package/lib/legal-hold.js +30 -23
- package/lib/log-stream-cloudwatch.js +44 -112
- package/lib/log-stream-otlp-grpc.js +17 -14
- package/lib/log-stream-otlp.js +16 -80
- package/lib/log-stream-webhook.js +20 -92
- package/lib/log.js +2 -2
- package/lib/mail-agent.js +2 -2
- package/lib/mail-arc-sign.js +8 -3
- package/lib/mail-arf.js +4 -3
- package/lib/mail-auth.js +43 -69
- package/lib/mail-bimi.js +35 -55
- package/lib/mail-bounce.js +3 -3
- package/lib/mail-crypto-pgp.js +3 -2
- package/lib/mail-crypto-smime.js +71 -6
- package/lib/mail-dav.js +8 -35
- package/lib/mail-deploy.js +15 -14
- package/lib/mail-dkim.js +19 -38
- package/lib/mail-greylist.js +17 -30
- package/lib/mail-helo.js +4 -7
- package/lib/mail-journal.js +13 -9
- package/lib/mail-mdn.js +12 -7
- package/lib/mail-rbl.js +7 -12
- package/lib/mail-scan.js +5 -7
- package/lib/mail-send-deliver.js +33 -20
- package/lib/mail-server-imap.js +32 -87
- package/lib/mail-server-jmap.js +39 -52
- package/lib/mail-server-managesieve.js +29 -83
- package/lib/mail-server-mx.js +33 -74
- package/lib/mail-server-net.js +177 -0
- package/lib/mail-server-pop3.js +30 -83
- package/lib/mail-server-rate-limit.js +30 -6
- package/lib/mail-server-registry.js +1 -1
- package/lib/mail-server-submission.js +34 -73
- package/lib/mail-server-tls.js +98 -2
- package/lib/mail-spam-score.js +9 -12
- package/lib/mail-store-fts.js +1 -1
- package/lib/mail-store.js +3 -2
- package/lib/mail.js +28 -13
- package/lib/markup-escape.js +31 -0
- package/lib/markup-tokenizer.js +78 -0
- package/lib/mcp-tool-registry.js +26 -23
- package/lib/mcp.js +7 -5
- package/lib/mdoc.js +36 -14
- package/lib/metrics.js +46 -33
- package/lib/middleware/age-gate.js +3 -23
- package/lib/middleware/api-encrypt.js +13 -24
- package/lib/middleware/assetlinks.js +2 -7
- package/lib/middleware/bearer-auth.js +2 -1
- package/lib/middleware/body-parser.js +41 -52
- package/lib/middleware/bot-disclose.js +7 -10
- package/lib/middleware/bot-guard.js +28 -28
- package/lib/middleware/clear-site-data.js +5 -1
- package/lib/middleware/compression.js +9 -0
- package/lib/middleware/cors.js +32 -23
- package/lib/middleware/csrf-protect.js +73 -23
- package/lib/middleware/daily-byte-quota.js +12 -30
- package/lib/middleware/deny-response.js +19 -1
- package/lib/middleware/fetch-metadata.js +35 -4
- package/lib/middleware/idempotency-key.js +4 -20
- package/lib/middleware/network-allowlist.js +61 -30
- package/lib/middleware/rate-limit.js +45 -44
- package/lib/middleware/scim-server.js +5 -3
- package/lib/middleware/security-headers.js +33 -7
- package/lib/middleware/security-txt.js +2 -6
- package/lib/middleware/speculation-rules.js +6 -3
- package/lib/middleware/tus-upload.js +14 -29
- package/lib/middleware/web-app-manifest.js +2 -7
- package/lib/migrations.js +4 -13
- package/lib/mime-parse.js +34 -17
- package/lib/module-loader.js +44 -0
- package/lib/money.js +105 -0
- package/lib/mtls-ca.js +125 -41
- package/lib/network-byte-quota.js +4 -18
- package/lib/network-dane.js +8 -6
- package/lib/network-dns-resolver.js +98 -7
- package/lib/network-dns.js +9 -2
- package/lib/network-dnssec.js +18 -17
- package/lib/network-heartbeat.js +3 -2
- package/lib/network-smtp-policy.js +52 -46
- package/lib/network-tls.js +67 -47
- package/lib/network-tsig.js +2 -2
- package/lib/nis2-report.js +2 -12
- package/lib/nist-crosswalk.js +1 -1
- package/lib/nonce-store.js +81 -3
- package/lib/ntp-check.js +28 -0
- package/lib/numeric-bounds.js +31 -8
- package/lib/object-store/azure-blob-bucket-ops.js +2 -6
- package/lib/object-store/azure-blob.js +6 -47
- package/lib/object-store/gcs-bucket-ops.js +4 -2
- package/lib/object-store/gcs.js +14 -75
- package/lib/object-store/http-put.js +2 -7
- package/lib/object-store/http-request.js +157 -0
- package/lib/object-store/local.js +37 -17
- package/lib/object-store/sigv4-bucket-ops.js +2 -1
- package/lib/object-store/sigv4.js +10 -79
- package/lib/observability-otlp-exporter.js +29 -29
- package/lib/observability.js +95 -0
- package/lib/openapi-paths-builder.js +7 -3
- package/lib/otel-export.js +7 -10
- package/lib/outbox.js +54 -41
- package/lib/pagination.js +11 -15
- package/lib/parsers/safe-env.js +5 -4
- package/lib/parsers/safe-ini.js +10 -4
- package/lib/parsers/safe-toml.js +11 -9
- package/lib/parsers/safe-xml.js +3 -3
- package/lib/parsers/safe-yaml.js +28 -9
- package/lib/pick.js +63 -5
- package/lib/pipl-cn.js +69 -59
- package/lib/privacy-pass.js +8 -6
- package/lib/problem-details.js +2 -5
- package/lib/pubsub.js +4 -8
- package/lib/queue-local.js +10 -3
- package/lib/redact.js +9 -4
- package/lib/render.js +4 -2
- package/lib/request-helpers.js +334 -29
- package/lib/resource-access-lock.js +3 -3
- package/lib/restore-bundle.js +46 -18
- package/lib/restore-rollback.js +10 -4
- package/lib/restore.js +24 -22
- package/lib/retention.js +23 -9
- package/lib/router.js +17 -4
- package/lib/safe-async.js +457 -0
- package/lib/safe-buffer.js +137 -6
- package/lib/safe-decompress.js +2 -1
- package/lib/safe-dns.js +2 -1
- package/lib/safe-ical.js +14 -28
- package/lib/safe-icap.js +1 -1
- package/lib/safe-json.js +51 -8
- package/lib/safe-jsonpath.js +6 -5
- package/lib/safe-mime.js +25 -29
- package/lib/safe-redirect.js +2 -5
- package/lib/safe-schema.js +7 -6
- package/lib/safe-sieve.js +1 -1
- package/lib/safe-sql.js +126 -0
- package/lib/safe-vcard.js +13 -27
- package/lib/sandbox-worker.js +15 -2
- package/lib/sandbox.js +4 -3
- package/lib/scheduler.js +22 -13
- package/lib/sec-cyber.js +82 -37
- package/lib/seeders.js +4 -11
- package/lib/self-update-standalone-verifier.js +16 -0
- package/lib/self-update.js +92 -69
- package/lib/session-device-binding.js +112 -66
- package/lib/session.js +219 -7
- package/lib/sql.js +228 -81
- package/lib/sse.js +6 -10
- package/lib/static.js +201 -111
- package/lib/storage.js +4 -2
- package/lib/structured-fields.js +275 -16
- package/lib/template.js +7 -5
- package/lib/tenant-quota.js +53 -38
- package/lib/tsa.js +16 -17
- package/lib/validate-opts.js +154 -8
- package/lib/vault/index.js +5 -0
- package/lib/vault/passphrase-ops.js +22 -26
- package/lib/vault/passphrase-source.js +8 -3
- package/lib/vault/rotate.js +13 -18
- package/lib/vault/seal-pem-file.js +34 -49
- package/lib/vault-aad.js +3 -2
- package/lib/vc.js +3 -8
- package/lib/vendor/MANIFEST.json +10 -10
- package/lib/vendor/public-suffix-list.dat +23 -10
- package/lib/vendor/public-suffix-list.data.js +5498 -5494
- package/lib/vex.js +35 -13
- package/lib/web-push-vapid.js +23 -20
- package/lib/webhook-dispatcher.js +706 -0
- package/lib/webhook.js +59 -19
- package/lib/websocket-channels.js +9 -7
- package/lib/websocket.js +8 -4
- package/lib/worm.js +3 -4
- package/lib/ws-client.js +65 -56
- package/lib/x509-chain.js +44 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/guard-graphql.js
CHANGED
|
@@ -81,7 +81,7 @@ var codepointClass = require("./codepoint-class");
|
|
|
81
81
|
var lazyRequire = require("./lazy-require");
|
|
82
82
|
var gateContract = require("./gate-contract");
|
|
83
83
|
var C = require("./constants");
|
|
84
|
-
var
|
|
84
|
+
var pick = require("./pick");
|
|
85
85
|
var { GuardGraphqlError } = require("./framework-error");
|
|
86
86
|
|
|
87
87
|
var observability = lazyRequire(function () { return require("./observability"); });
|
|
@@ -100,10 +100,7 @@ var PROTO_POISON_QUERY_RE = /[\s,({:]\$?(?:__proto__|constructor|prototype)\b/;
|
|
|
100
100
|
|
|
101
101
|
var PROFILES = Object.freeze({
|
|
102
102
|
"strict": {
|
|
103
|
-
|
|
104
|
-
controlPolicy: "reject",
|
|
105
|
-
nullBytePolicy: "reject",
|
|
106
|
-
zeroWidthPolicy: "reject",
|
|
103
|
+
...gateContract.CHAR_THREATS_REJECT_ALL,
|
|
107
104
|
introspectionPolicy: "reject",
|
|
108
105
|
persistedQueryPolicy: "audit",
|
|
109
106
|
operationNamePolicy: "audit",
|
|
@@ -120,10 +117,7 @@ var PROFILES = Object.freeze({
|
|
|
120
117
|
maxRuntimeMs: C.TIME.seconds(2),
|
|
121
118
|
},
|
|
122
119
|
"balanced": {
|
|
123
|
-
|
|
124
|
-
controlPolicy: "reject",
|
|
125
|
-
nullBytePolicy: "reject",
|
|
126
|
-
zeroWidthPolicy: "reject",
|
|
120
|
+
...gateContract.CHAR_THREATS_REJECT_ALL,
|
|
127
121
|
introspectionPolicy: "audit",
|
|
128
122
|
persistedQueryPolicy: "audit",
|
|
129
123
|
operationNamePolicy: "audit",
|
|
@@ -140,10 +134,7 @@ var PROFILES = Object.freeze({
|
|
|
140
134
|
maxRuntimeMs: C.TIME.seconds(2),
|
|
141
135
|
},
|
|
142
136
|
"permissive": {
|
|
143
|
-
|
|
144
|
-
controlPolicy: "reject", // controls refused at every profile
|
|
145
|
-
nullBytePolicy: "reject", // null refused at every profile
|
|
146
|
-
zeroWidthPolicy: "reject", // zero-width refused at every profile
|
|
137
|
+
...gateContract.CHAR_THREATS_REJECT_ALL,
|
|
147
138
|
introspectionPolicy: "allow",
|
|
148
139
|
persistedQueryPolicy: "allow",
|
|
149
140
|
operationNamePolicy: "allow",
|
|
@@ -161,35 +152,6 @@ var PROFILES = Object.freeze({
|
|
|
161
152
|
},
|
|
162
153
|
});
|
|
163
154
|
|
|
164
|
-
var DEFAULTS = Object.freeze(Object.assign({}, PROFILES["strict"], {
|
|
165
|
-
mode: "enforce",
|
|
166
|
-
}));
|
|
167
|
-
|
|
168
|
-
var COMPLIANCE_POSTURES = Object.freeze({
|
|
169
|
-
"hipaa": Object.assign({}, PROFILES["strict"], {
|
|
170
|
-
forensicSnippetBytes: C.BYTES.bytes(512),
|
|
171
|
-
}),
|
|
172
|
-
"pci-dss": Object.assign({}, PROFILES["strict"], {
|
|
173
|
-
forensicSnippetBytes: C.BYTES.bytes(512),
|
|
174
|
-
}),
|
|
175
|
-
"gdpr": Object.assign({}, PROFILES["balanced"], {
|
|
176
|
-
forensicSnippetBytes: C.BYTES.bytes(256),
|
|
177
|
-
}),
|
|
178
|
-
"soc2": Object.assign({}, PROFILES["strict"], {
|
|
179
|
-
forensicSnippetBytes: C.BYTES.bytes(1024),
|
|
180
|
-
}),
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
function _resolveOpts(opts) {
|
|
184
|
-
return gateContract.resolveProfileAndPosture(opts, {
|
|
185
|
-
profiles: PROFILES,
|
|
186
|
-
compliancePostures: COMPLIANCE_POSTURES,
|
|
187
|
-
defaults: DEFAULTS,
|
|
188
|
-
errorClass: GuardGraphqlError,
|
|
189
|
-
errCodePrefix: "graphql",
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
|
|
193
155
|
// _measureQueryShape — walks the query string and computes
|
|
194
156
|
// brace-depth + per-selection-set alias counts using simple paren
|
|
195
157
|
// counting. Not a full GraphQL parser (operator runs the schema-
|
|
@@ -333,9 +295,7 @@ function _detectIssues(req, opts) {
|
|
|
333
295
|
var pVar = req.variables;
|
|
334
296
|
var pHas = Object.prototype.hasOwnProperty;
|
|
335
297
|
var pName = (pVar && typeof pVar === "object" && !Array.isArray(pVar) &&
|
|
336
|
-
(pHas.call(pVar,
|
|
337
|
-
pHas.call(pVar, "constructor") ? "constructor" :
|
|
338
|
-
pHas.call(pVar, "prototype") ? "prototype" : null));
|
|
298
|
+
pick.POISONED_KEYS.find(function (pk) { return pHas.call(pVar, pk); })) || null;
|
|
339
299
|
if (pName) {
|
|
340
300
|
issues.push({
|
|
341
301
|
kind: "variable-prototype-poison", severity: "critical",
|
|
@@ -500,14 +460,11 @@ function _detectIssues(req, opts) {
|
|
|
500
460
|
* var ok = b.guardGraphql.validate(benign, { profile: "strict" });
|
|
501
461
|
* ok.ok; // → true
|
|
502
462
|
*/
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
"guardGraphql.validate", GuardGraphqlError, "graphql.bad-opt");
|
|
509
|
-
return gateContract.aggregateIssues(_detectIssues(input, opts));
|
|
510
|
-
}
|
|
463
|
+
// validate is assembled by gateContract.defineGuard from `detect`
|
|
464
|
+
// (_detectIssues) below — `validate(input, opts) = aggregateIssues(detect(
|
|
465
|
+
// input, resolveOpts(opts)))`, with the byte / depth / alias / batch caps
|
|
466
|
+
// declared via `intOpts`. The @primitive block above documents the
|
|
467
|
+
// resulting public ABI.
|
|
511
468
|
|
|
512
469
|
/**
|
|
513
470
|
* @primitive b.guardGraphql.sanitize
|
|
@@ -539,10 +496,11 @@ function validate(input, opts) {
|
|
|
539
496
|
* e.code; // → "graphql.introspection"
|
|
540
497
|
* }
|
|
541
498
|
*/
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
499
|
+
// _sanitizeTransform — the guard-specific normalize applied by defineGuard's
|
|
500
|
+
// generated sanitize AFTER resolve → detect → throw-on-refusal. GraphQL
|
|
501
|
+
// request bundles can't be partially repaired; once detection passes with no
|
|
502
|
+
// critical/high issue, the input is returned unchanged.
|
|
503
|
+
function _sanitizeTransform(input) {
|
|
546
504
|
return input;
|
|
547
505
|
}
|
|
548
506
|
|
|
@@ -583,25 +541,19 @@ function sanitize(input, opts) {
|
|
|
583
541
|
* rv.issues[0].ruleId; // → "graphql.alias-bomb"
|
|
584
542
|
*/
|
|
585
543
|
function gate(opts) {
|
|
586
|
-
opts =
|
|
544
|
+
opts = _guard.resolveOpts(opts);
|
|
587
545
|
return gateContract.buildGuardGate(
|
|
588
546
|
opts.name || "guardGraphql:" + (opts.profile || "default"),
|
|
589
547
|
opts,
|
|
590
548
|
async function (ctx) {
|
|
591
549
|
var req = ctx && (ctx.graphqlRequest || ctx.gql);
|
|
592
550
|
if (!req) return { ok: true, action: "serve" };
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
return i.severity === "high";
|
|
600
|
-
});
|
|
601
|
-
if (!hasCritical && !hasHigh) {
|
|
602
|
-
return { ok: true, action: "audit-only", issues: rv.issues };
|
|
603
|
-
}
|
|
604
|
-
return { ok: false, action: "refuse", issues: rv.issues };
|
|
551
|
+
// validate is assembled by defineGuard (from `detect` below) and lives
|
|
552
|
+
// on the frozen module.exports; the gate is only invoked at runtime,
|
|
553
|
+
// after the export is assigned. Behaviour is identical to the prior
|
|
554
|
+
// local validate (resolve → intOpts → aggregateIssues(detect)).
|
|
555
|
+
var rv = module.exports.validate(req, opts);
|
|
556
|
+
return gateContract.severityDisposition(rv.issues);
|
|
605
557
|
});
|
|
606
558
|
}
|
|
607
559
|
|
|
@@ -636,15 +588,16 @@ var INTEGRATION_FIXTURES = Object.freeze({
|
|
|
636
588
|
// surface (validate / sanitize / bespoke gate) passed through verbatim.
|
|
637
589
|
// The custom KIND ("graphql-request") is accepted because the bespoke
|
|
638
590
|
// gate reads its own ctx fields (ctx.graphqlRequest / ctx.gql).
|
|
639
|
-
module.exports = gateContract.defineGuard({
|
|
591
|
+
var _guard = module.exports = gateContract.defineGuard({
|
|
640
592
|
name: "graphql",
|
|
641
593
|
kind: "graphql-request",
|
|
642
594
|
errorClass: GuardGraphqlError,
|
|
643
595
|
profiles: PROFILES,
|
|
644
|
-
|
|
645
|
-
postures: COMPLIANCE_POSTURES,
|
|
596
|
+
base: 512,
|
|
646
597
|
integrationFixtures: INTEGRATION_FIXTURES,
|
|
647
|
-
|
|
648
|
-
|
|
598
|
+
detect: _detectIssues,
|
|
599
|
+
sanitizeTransform: _sanitizeTransform,
|
|
600
|
+
intOpts: ["maxBytes", "maxQueryBytes", "maxVariableBytes",
|
|
601
|
+
"maxDepth", "maxAliasesPerSelection", "maxBatchSize"],
|
|
649
602
|
gate: gate,
|
|
650
603
|
});
|
package/lib/guard-html-wcag.js
CHANGED
|
@@ -82,6 +82,19 @@ var _TAG_RE = tagwalk.TAG_RE;
|
|
|
82
82
|
var _parseAttrs = tagwalk.parseAttrs;
|
|
83
83
|
var _lineColAt = tagwalk.lineColAt;
|
|
84
84
|
|
|
85
|
+
// Strip every HTML tag for plain-text measurement. Re-runs the tag regex
|
|
86
|
+
// until the string is stable so nested-bracket residue (e.g. `<scr<x>ipt>`)
|
|
87
|
+
// cannot survive a single pass. Output is used only for text-length / content
|
|
88
|
+
// checks, never re-emitted as HTML.
|
|
89
|
+
function _stripTags(s) {
|
|
90
|
+
var prev;
|
|
91
|
+
do {
|
|
92
|
+
prev = s;
|
|
93
|
+
s = s.replace(/<[^>]+>/g, "");
|
|
94
|
+
} while (s !== prev);
|
|
95
|
+
return s;
|
|
96
|
+
}
|
|
97
|
+
|
|
85
98
|
function _innerText(html, tagOpenEnd, tagName) {
|
|
86
99
|
var lower = tagName.toLowerCase();
|
|
87
100
|
var closeRe = new RegExp("</\\s*" + lower + "\\s*>", "i"); // allow:dynamic-regex — `lower` is a tag name from the framework's static SC registry, not operator input; `\\s*` and tag name are RegExp-safe (no special chars)
|
|
@@ -89,7 +102,7 @@ function _innerText(html, tagOpenEnd, tagName) {
|
|
|
89
102
|
var m = closeRe.exec(html);
|
|
90
103
|
if (!m) return "";
|
|
91
104
|
var raw = html.slice(tagOpenEnd, m.index);
|
|
92
|
-
return raw
|
|
105
|
+
return _stripTags(raw).replace(/&[a-z]+;|&#\d+;/gi, "").trim();
|
|
93
106
|
}
|
|
94
107
|
|
|
95
108
|
// ---- Per-element checks ----
|
|
@@ -270,7 +283,7 @@ function _checkPageTitle(html, report, opts) {
|
|
|
270
283
|
});
|
|
271
284
|
return;
|
|
272
285
|
}
|
|
273
|
-
var title = m[1]
|
|
286
|
+
var title = _stripTags(m[1]).trim();
|
|
274
287
|
if (title.length === 0) {
|
|
275
288
|
var pos2 = _lineColAt(html, m.index);
|
|
276
289
|
_addFinding(report, {
|
package/lib/guard-html.js
CHANGED
|
@@ -93,6 +93,8 @@
|
|
|
93
93
|
*/
|
|
94
94
|
|
|
95
95
|
var codepointClass = require("./codepoint-class");
|
|
96
|
+
var markupTokenizer = require("./markup-tokenizer");
|
|
97
|
+
var markupEscape = require("./markup-escape").markupEscape;
|
|
96
98
|
var guardHtmlWcag = require("./guard-html-wcag");
|
|
97
99
|
var lazyRequire = require("./lazy-require");
|
|
98
100
|
var gateContract = require("./gate-contract");
|
|
@@ -105,7 +107,6 @@ var observability = lazyRequire(function () { return require("./observability");
|
|
|
105
107
|
void observability;
|
|
106
108
|
|
|
107
109
|
var _err = GuardHtmlError.factory;
|
|
108
|
-
var HEX_RADIX = 16; // base-16 radix, not byte size
|
|
109
110
|
|
|
110
111
|
// ---- Codepoint catalog (shared via lib/codepoint-class) ----
|
|
111
112
|
|
|
@@ -179,16 +180,14 @@ var URL_ATTRS = Object.freeze([
|
|
|
179
180
|
]);
|
|
180
181
|
|
|
181
182
|
// Always-allowed schemes (every profile).
|
|
182
|
-
var SAFE_SCHEMES =
|
|
183
|
+
var SAFE_SCHEMES = gateContract.SAFE_URL_SCHEMES;
|
|
183
184
|
|
|
184
185
|
// Schemes denied by default. `data` is dangerous globally except in
|
|
185
186
|
// image context (data:image/*) which is the only data: payload that
|
|
186
187
|
// can't directly script the page; the per-attribute check below honours
|
|
187
188
|
// that exception when allowImageData=true and the host tag is <img>.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
"file", "mhtml", "jar", "intent", "view-source", "feed", "data",
|
|
191
|
-
]);
|
|
189
|
+
// Markup-attribute scheme denylist — the shared XSS / dangerous-resource set.
|
|
190
|
+
var DANGEROUS_SCHEMES = gateContract.DANGEROUS_URL_SCHEMES;
|
|
192
191
|
|
|
193
192
|
// CSS dangerous tokens — case-insensitive match against attribute
|
|
194
193
|
// value content.
|
|
@@ -291,54 +290,12 @@ var PROFILES = Object.freeze({
|
|
|
291
290
|
},
|
|
292
291
|
});
|
|
293
292
|
|
|
294
|
-
var DEFAULTS =
|
|
295
|
-
mode: "enforce",
|
|
293
|
+
var DEFAULTS = gateContract.strictDefaults(PROFILES, {
|
|
296
294
|
maxRuntimeMs: C.TIME.seconds(30),
|
|
297
|
-
}));
|
|
298
|
-
|
|
299
|
-
var COMPLIANCE_POSTURES = Object.freeze({
|
|
300
|
-
"hipaa": {
|
|
301
|
-
allowedTags: STRICT_ALLOWED_TAGS,
|
|
302
|
-
bidiPolicy: "reject",
|
|
303
|
-
controlPolicy: "reject",
|
|
304
|
-
nullBytePolicy: "reject",
|
|
305
|
-
cssPolicy: "reject",
|
|
306
|
-
domClobberPolicy: "reject",
|
|
307
|
-
mxssHintPolicy: "reject",
|
|
308
|
-
forensicSnippetBytes: C.BYTES.bytes(256),
|
|
309
|
-
},
|
|
310
|
-
"pci-dss": {
|
|
311
|
-
allowedTags: STRICT_ALLOWED_TAGS,
|
|
312
|
-
bidiPolicy: "reject",
|
|
313
|
-
controlPolicy: "reject",
|
|
314
|
-
nullBytePolicy: "reject",
|
|
315
|
-
cssPolicy: "reject",
|
|
316
|
-
domClobberPolicy: "reject",
|
|
317
|
-
mxssHintPolicy: "reject",
|
|
318
|
-
urlSchemes: SAFE_SCHEMES,
|
|
319
|
-
forensicSnippetBytes: C.BYTES.bytes(256),
|
|
320
|
-
},
|
|
321
|
-
"gdpr": {
|
|
322
|
-
allowedTags: BALANCED_ALLOWED_TAGS,
|
|
323
|
-
bidiPolicy: "strip",
|
|
324
|
-
controlPolicy: "strip",
|
|
325
|
-
cssPolicy: "strip",
|
|
326
|
-
domClobberPolicy: "strip",
|
|
327
|
-
mxssHintPolicy: "audit",
|
|
328
|
-
forensicSnippetBytes: C.BYTES.bytes(128),
|
|
329
|
-
},
|
|
330
|
-
"soc2": {
|
|
331
|
-
allowedTags: STRICT_ALLOWED_TAGS,
|
|
332
|
-
bidiPolicy: "reject",
|
|
333
|
-
controlPolicy: "reject",
|
|
334
|
-
nullBytePolicy: "reject",
|
|
335
|
-
cssPolicy: "reject",
|
|
336
|
-
domClobberPolicy: "reject",
|
|
337
|
-
mxssHintPolicy: "reject",
|
|
338
|
-
forensicSnippetBytes: C.BYTES.bytes(512),
|
|
339
|
-
},
|
|
340
295
|
});
|
|
341
296
|
|
|
297
|
+
var COMPLIANCE_POSTURES = gateContract.compliancePostures(PROFILES, { base: 256 });
|
|
298
|
+
|
|
342
299
|
// ---- Internal helpers ----
|
|
343
300
|
|
|
344
301
|
function _resolveOpts(opts) {
|
|
@@ -372,12 +329,7 @@ function _resolveOpts(opts) {
|
|
|
372
329
|
*/
|
|
373
330
|
function escapeText(value) {
|
|
374
331
|
var s = value == null ? "" : String(value);
|
|
375
|
-
return s
|
|
376
|
-
.replace(/&/g, "&")
|
|
377
|
-
.replace(/</g, "<")
|
|
378
|
-
.replace(/>/g, ">")
|
|
379
|
-
.replace(/"/g, """)
|
|
380
|
-
.replace(/'/g, "'");
|
|
332
|
+
return markupEscape(s, { apos: "'" });
|
|
381
333
|
}
|
|
382
334
|
|
|
383
335
|
/**
|
|
@@ -401,12 +353,9 @@ function escapeText(value) {
|
|
|
401
353
|
*/
|
|
402
354
|
function escapeAttr(value) {
|
|
403
355
|
var s = value == null ? "" : String(value);
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
.replace(/>/g, ">")
|
|
408
|
-
.replace(/"/g, """)
|
|
409
|
-
.replace(/'/g, "'")
|
|
356
|
+
// Base markup chars + apostrophe via markupEscape; the backtick + "="
|
|
357
|
+
// escapes are the IE attribute-injection hardening unique to this escaper.
|
|
358
|
+
return markupEscape(s, { apos: "'" })
|
|
410
359
|
.replace(/`/g, "`")
|
|
411
360
|
.replace(/=/g, "=");
|
|
412
361
|
}
|
|
@@ -440,14 +389,11 @@ var NAMED_ENTITY_ASCII = {
|
|
|
440
389
|
// scheme. Returns "" if no scheme.
|
|
441
390
|
function _extractScheme(rawUrl) {
|
|
442
391
|
var s = String(rawUrl || "").trim();
|
|
443
|
-
// Decode HTML numeric entities
|
|
444
|
-
// like javascript
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
s = s.replace(/&#(\d+);/g, function (_m, d) {
|
|
449
|
-
return String.fromCharCode(parseInt(d, 10));
|
|
450
|
-
});
|
|
392
|
+
// Decode HTML numeric entities (hex &#x..; and decimal &#..;, semicolon
|
|
393
|
+
// OPTIONAL) just enough to expose hidden schemes like javascript: or
|
|
394
|
+
// the browser-decoded no-semicolon form javascript:. Shared decoder so
|
|
395
|
+
// guard-html / guard-svg / guard-markdown can't drift (see codepoint-class).
|
|
396
|
+
s = codepointClass.decodeNumericEntities(s);
|
|
451
397
|
// Decode HTML5 named entities that browsers honor inside URL
|
|
452
398
|
// contexts. Without this, payloads like `java	script:alert(1)`
|
|
453
399
|
// bypass the scheme allowlist (the literal `	` between `java`
|
|
@@ -511,9 +457,10 @@ function _isCssDangerous(value) {
|
|
|
511
457
|
|
|
512
458
|
function _tokenize(input, maxBytes) {
|
|
513
459
|
var s = String(input || "");
|
|
514
|
-
|
|
460
|
+
var nb = Buffer.byteLength(s, "utf8");
|
|
461
|
+
if (nb > maxBytes) {
|
|
515
462
|
throw _err("html.too-large",
|
|
516
|
-
"input " +
|
|
463
|
+
"input " + nb + " bytes exceeds maxBytes " + maxBytes);
|
|
517
464
|
}
|
|
518
465
|
var tokens = [];
|
|
519
466
|
var len = s.length;
|
|
@@ -531,9 +478,11 @@ function _tokenize(input, maxBytes) {
|
|
|
531
478
|
|
|
532
479
|
// Comment / CDATA / doctype
|
|
533
480
|
if (s.startsWith("<!--", lt)) {
|
|
534
|
-
|
|
481
|
+
// WHATWG comment end (covers "--!>" + abrupt "<!-->" / "<!--->"), not
|
|
482
|
+
// only "-->", so a smuggled element after an early terminator is split
|
|
483
|
+
// out as a live token instead of hidden inside the comment (mXSS).
|
|
484
|
+
var endC = markupTokenizer.htmlCommentEnd(s, lt);
|
|
535
485
|
if (endC === -1) endC = len;
|
|
536
|
-
else endC += 3;
|
|
537
486
|
tokens.push({ type: "comment", raw: s.slice(lt, endC), start: lt, end: endC });
|
|
538
487
|
pos = endC; continue;
|
|
539
488
|
}
|
|
@@ -567,28 +516,15 @@ function _tokenize(input, maxBytes) {
|
|
|
567
516
|
|
|
568
517
|
// Start tag — find the matching `>`, but skip over `>` inside
|
|
569
518
|
// quoted attribute values.
|
|
570
|
-
var p = lt + 1;
|
|
571
|
-
var inQuote = "";
|
|
572
|
-
while (p < len) {
|
|
573
|
-
var ch = s.charAt(p);
|
|
574
|
-
if (inQuote) {
|
|
575
|
-
if (ch === inQuote) inQuote = "";
|
|
576
|
-
} else {
|
|
577
|
-
if (ch === '"' || ch === "'") inQuote = ch;
|
|
578
|
-
else if (ch === ">") break;
|
|
579
|
-
}
|
|
580
|
-
p += 1;
|
|
581
|
-
}
|
|
519
|
+
var p = markupTokenizer.scanToTagEnd(s, lt + 1, len);
|
|
582
520
|
var endT = p < len ? p + 1 : len;
|
|
583
521
|
var raw = s.slice(lt, endT);
|
|
584
522
|
var inner = raw.slice(1, raw.charAt(raw.length - 1) === ">" ? raw.length - 1 : raw.length);
|
|
585
523
|
if (inner.endsWith("/")) inner = inner.slice(0, inner.length - 1);
|
|
586
524
|
|
|
587
|
-
var
|
|
588
|
-
var tagName =
|
|
589
|
-
var
|
|
590
|
-
|
|
591
|
-
var attrs = _parseAttrs(attrSrc);
|
|
525
|
+
var htmlParts = markupTokenizer.splitTagNameAttrs(inner, /^([A-Za-z][A-Za-z0-9:-]*)/);
|
|
526
|
+
var tagName = htmlParts.tagName;
|
|
527
|
+
var attrs = _parseAttrs(htmlParts.attrSrc);
|
|
592
528
|
tokens.push({
|
|
593
529
|
type: "tag", name: tagName, attrs: attrs,
|
|
594
530
|
raw: raw, start: lt, end: endT,
|
|
@@ -643,7 +579,7 @@ function _parseAttrs(src) {
|
|
|
643
579
|
function _detectIssues(input, opts) {
|
|
644
580
|
var s = String(input || "");
|
|
645
581
|
// 1. Whole-input bidi / null-byte / control char threats.
|
|
646
|
-
var issues = codepointClass.detectCharThreats(s, opts, "html");
|
|
582
|
+
var issues = codepointClass.detectCharThreats(s, opts, "html", "warn");
|
|
647
583
|
|
|
648
584
|
var tokens;
|
|
649
585
|
try { tokens = _tokenize(s, opts.maxBytes); }
|
|
@@ -712,7 +648,7 @@ function _detectIssues(input, opts) {
|
|
|
712
648
|
for (var ai = 0; ai < attrs.length; ai += 1) {
|
|
713
649
|
var a = attrs[ai];
|
|
714
650
|
var an = a.name.toLowerCase();
|
|
715
|
-
if (a.value && a.value
|
|
651
|
+
if (a.value && Buffer.byteLength(a.value, "utf8") > opts.maxAttrValueBytes) {
|
|
716
652
|
issues.push({
|
|
717
653
|
kind: "attr-value-too-large", severity: "high",
|
|
718
654
|
ruleId: "html.attr-size",
|
|
@@ -814,9 +750,10 @@ function _detectIssues(input, opts) {
|
|
|
814
750
|
|
|
815
751
|
function _sanitize(input, opts) {
|
|
816
752
|
var s = String(input || "");
|
|
817
|
-
|
|
753
|
+
var nb = Buffer.byteLength(s, "utf8");
|
|
754
|
+
if (nb > opts.maxBytes) {
|
|
818
755
|
throw _err("html.too-large",
|
|
819
|
-
"input " +
|
|
756
|
+
"input " + nb + " bytes exceeds maxBytes " + opts.maxBytes);
|
|
820
757
|
}
|
|
821
758
|
codepointClass.assertNoCharThreats(s, opts, _err, "html");
|
|
822
759
|
s = codepointClass.applyCharStripPolicies(s, opts);
|
|
@@ -884,7 +821,7 @@ function _sanitize(input, opts) {
|
|
|
884
821
|
if (EVENT_HANDLER_RE.test(an)) continue;
|
|
885
822
|
if (DANGEROUS_ATTRS.indexOf(an) !== -1) continue;
|
|
886
823
|
if (Object.keys(allowedAttrs).length > 0 && !allowedAttrs[an]) continue;
|
|
887
|
-
if (a.value && a.value
|
|
824
|
+
if (a.value && Buffer.byteLength(a.value, "utf8") > opts.maxAttrValueBytes) continue;
|
|
888
825
|
if (_isUrlAttr(an)) {
|
|
889
826
|
var scheme = _extractScheme(a.value);
|
|
890
827
|
if (scheme && DANGEROUS_SCHEMES.indexOf(scheme) !== -1) {
|
|
@@ -1061,39 +998,47 @@ function sanitize(input, opts) {
|
|
|
1061
998
|
* rv.ok; // → false
|
|
1062
999
|
* rv.action; // → "refuse"
|
|
1063
1000
|
*/
|
|
1001
|
+
// Disposition of each html finding = what the operator's policy for that class
|
|
1002
|
+
// selected. The configurable classes (CSS injection / DOM-clobbering / mXSS
|
|
1003
|
+
// hint) and the bidi / null / control char threats follow their policies
|
|
1004
|
+
// (sanitize under `strip`, refuse under `reject`, audit under `audit`). The
|
|
1005
|
+
// always-dangerous denylist (dangerous tag / event handler / dangerous attr /
|
|
1006
|
+
// dangerous URL scheme) refuses — stripping a script-equivalent is not a
|
|
1007
|
+
// provable repair (an mXSS / parser-differential vector can survive); a
|
|
1008
|
+
// non-allowlisted but otherwise-benign tag / scheme sanitizes (the allowlist
|
|
1009
|
+
// sanitizer drops it); structural caps and a tokenizer failure refuse.
|
|
1010
|
+
// Exhaustive over every kind the detection pass emits.
|
|
1011
|
+
function _gateDispositionFor(issue, opts) {
|
|
1012
|
+
var shared = gateContract.charThreatDisposition(issue, opts);
|
|
1013
|
+
if (shared) return shared;
|
|
1014
|
+
switch (issue.kind) {
|
|
1015
|
+
case "css-injection": return gateContract.policyDisposition(opts.cssPolicy);
|
|
1016
|
+
case "dom-clobber": return gateContract.policyDisposition(opts.domClobberPolicy);
|
|
1017
|
+
case "mxss-hint": return gateContract.policyDisposition(opts.mxssHintPolicy);
|
|
1018
|
+
case "non-allowlisted-tag":
|
|
1019
|
+
case "non-allowlisted-url-scheme": return "sanitize";
|
|
1020
|
+
case "dangerous-tag":
|
|
1021
|
+
case "event-handler":
|
|
1022
|
+
case "dangerous-attr":
|
|
1023
|
+
case "dangerous-url-scheme": return "refuse";
|
|
1024
|
+
case "tokenize-failed":
|
|
1025
|
+
case "ie-conditional-comment":
|
|
1026
|
+
case "depth-cap":
|
|
1027
|
+
case "attr-count-cap":
|
|
1028
|
+
case "attr-value-too-large": return "refuse";
|
|
1029
|
+
default: return null;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1064
1033
|
function gate(opts) {
|
|
1065
1034
|
opts = _resolveOpts(opts);
|
|
1066
|
-
return gateContract.
|
|
1067
|
-
opts.name || "guardHtml:" + (opts.profile || "default"),
|
|
1068
|
-
opts,
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
if (rv.issues.length === 0) return { ok: true, action: "serve" };
|
|
1074
|
-
var hasCritical = rv.issues.some(function (i) {
|
|
1075
|
-
return i.severity === "critical" || i.severity === "high";
|
|
1076
|
-
});
|
|
1077
|
-
if (!hasCritical) return { ok: true, action: "audit-only", issues: rv.issues };
|
|
1078
|
-
|
|
1079
|
-
// Sanitize attempt — only when no policy says reject.
|
|
1080
|
-
if (opts.bidiPolicy !== "reject" &&
|
|
1081
|
-
opts.controlPolicy !== "reject" &&
|
|
1082
|
-
opts.nullBytePolicy !== "reject" &&
|
|
1083
|
-
opts.cssPolicy !== "reject" &&
|
|
1084
|
-
opts.domClobberPolicy !== "reject" &&
|
|
1085
|
-
opts.mxssHintPolicy !== "reject") {
|
|
1086
|
-
try {
|
|
1087
|
-
var clean = sanitize(text, opts);
|
|
1088
|
-
return {
|
|
1089
|
-
ok: true, action: "sanitize",
|
|
1090
|
-
sanitized: Buffer.from(clean, "utf8"),
|
|
1091
|
-
issues: rv.issues,
|
|
1092
|
-
};
|
|
1093
|
-
} catch (_e) { /* fall through */ }
|
|
1094
|
-
}
|
|
1095
|
-
return { ok: false, action: "refuse", issues: rv.issues };
|
|
1096
|
-
});
|
|
1035
|
+
return gateContract.buildContentGate({
|
|
1036
|
+
name: opts.name || "guardHtml:" + (opts.profile || "default"),
|
|
1037
|
+
opts: opts,
|
|
1038
|
+
validate: validate,
|
|
1039
|
+
dispositionFor: _gateDispositionFor,
|
|
1040
|
+
produceSanitized: function (text, o) { return sanitize(text, o); },
|
|
1041
|
+
});
|
|
1097
1042
|
}
|
|
1098
1043
|
|
|
1099
1044
|
// buildProfile / compliancePosture / loadRulePack are assembled by
|
|
@@ -1135,6 +1080,7 @@ module.exports = gateContract.defineGuard({
|
|
|
1135
1080
|
sanitize: sanitize,
|
|
1136
1081
|
gate: gate,
|
|
1137
1082
|
extra: {
|
|
1083
|
+
_gateDispositionForTest: _gateDispositionFor,
|
|
1138
1084
|
escapeText: escapeText,
|
|
1139
1085
|
escapeAttr: escapeAttr,
|
|
1140
1086
|
DANGEROUS_TAGS: DANGEROUS_TAGS,
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
var { defineClass } = require("./framework-error");
|
|
33
33
|
var gateContract = require("./gate-contract");
|
|
34
|
+
var codepointClass = require("./codepoint-class");
|
|
34
35
|
|
|
35
36
|
var GuardIdempotencyKeyError = defineClass("GuardIdempotencyKeyError", { alwaysPermanent: true });
|
|
36
37
|
|
|
@@ -90,7 +91,7 @@ function validate(value, opts) {
|
|
|
90
91
|
// C0 / DEL / slash refusal.
|
|
91
92
|
for (var i = 0; i < value.length; i += 1) {
|
|
92
93
|
var c = value.charCodeAt(i);
|
|
93
|
-
if (c
|
|
94
|
+
if (codepointClass.isForbiddenControlChar(c, { forbidTab: true })) { // C0 + DEL refusal
|
|
94
95
|
throw new GuardIdempotencyKeyError("idempotency-key/control-char",
|
|
95
96
|
"guardIdempotencyKey.validate: control char 0x" + c.toString(16) + " at offset " + i);
|
|
96
97
|
}
|