Skip to content

Tags: aegif/NemakiWare

Tags

v3.2.0

Toggle v3.2.0's commit message
NemakiWare 3.2.0 — IaaS one-step deployment (images + bootstrap + Ter…

…raform), validated via CI smoke

v3.1.1-RC6.13

Toggle v3.1.1-RC6.13's commit message
v3.1.1-RC6.13 — Test quality: feature-readback now binds to productio…

…n reader (closes RC6.12 P3)

Test-quality follow-up to RC6.12. Production SAXReader
configuration unchanged (byte-equivalent — three setFeature
calls just split into a new configureHardenedSaxReader() helper
that parseAcpPackageXml now delegates to).

Closes RC6.12 external review P3: feature-readback assertion
was inspecting a test-local probe, not the production-configured
reader. Restructured so the readback queries
ZipImporter.configureHardenedSaxReader() directly.

3-way mutation test verified: each of the three setFeature
lines, removed in isolation, fails the matching readback
assertion. Disallow-doctype removal additionally fails the 2
DOCTYPE-rejection cases. After restore: 4/4 PASS.

Tests: ZipImporterXxeTest 4/4 PASS, focused 25-class regression
377/377 PASS (same count as RC6.12), SOC validator 17 PASS /
7 SKIP, NUL scan 1681 source files / 0 hits.

No public API change. No property change. No schema / patch /
view / Mango / migration change. Operators see zero
behavioural difference. RC6.11 GHSA XXE security boundary is
unchanged; RC6.12 production path behaviour is unchanged.

Base: v3.1.1-RC6.12 (peeled f8ec032).

v3.1.1-RC6.12

Toggle v3.1.1-RC6.12's commit message
v3.1.1-RC6.12 — Test quality: bind XXE regression to production parser

Test-quality follow-up to the RC6.11 GHSA XXE fix. Production
SAXReader configuration unchanged (byte-equivalent — three
setFeature calls just moved from inline inside importAcpFormat to
inside a new package-private parseAcpPackageXml helper that it
now delegates to).

Closes two RC6.11 external review findings:
- P2: ZipImporterXxeTest now calls ZipImporter.parseAcpPackageXml
  directly. Mutation-test verified: removing the production
  disallow-doctype-decl line causes 2/4 cases to fail.
- P3: NUL scan file count corrected from "1683" (RC6.11 doc
  arithmetic error) to 1681 (validator's actual output) across
  RELEASE_NOTES, CLAUDE, REVIEW_PACKET.

Tests: ZipImporterXxeTest 4/4 PASS via production helper. Focused
25-class regression 377/377 PASS (same count as RC6.11). SOC
validator 17 PASS / 7 SKIP, NUL scan 1681 source files / 0 hits.

No public API change. No property change. No schema / patch /
view / Mango index change. Operators see zero behavioural
difference. RC6.11 GHSA XXE security boundary is unchanged.

Base: v3.1.1-RC6.11 (peeled 8e52d95).

v3.1.1-RC6.11

Toggle v3.1.1-RC6.11's commit message
v3.1.1-RC6.11 — Security: XXE on ACP import (CWE-611, GHSA, reporter …

…tonghuaroot)

High-severity security hotfix. ZipImporter.importAcpFormat() now
configures its dom4j SAXReader with disallow-doctype-decl +
external-general-entities=false + external-parameter-entities=false,
mirroring the existing TypeResource.parse() pattern (since RC13).

Closes a read-capable XXE reachable by any authenticated user with
cmis:write on a single folder. Reporter PoC reproduced live on the
deployed RC6.10 stack with non-admin "bob" user: /etc/passwd
leaked verbatim as a CMIS folder name. Post-fix: same upload
rejected with "DOCTYPE is disallowed" diagnostic.

Repo-wide audit: every other XML parser sink already hardened
(TypeResource RC13, AuthTokenResource SAML response RC13,
SolrResource RC13, SolrAllResource RC13, SamlSignatureVerifier
parses no XML itself).

Tests: ZipImporterXxeTest 4/4 PASS (new) + focused 25-class
regression 377/377 PASS (was 373 in RC6.10; +4).

Reported by tonghuaroot via GitHub Security Advisory (same
external reporter as the RC6.5 SSRF advisory).

Base: v3.1.1-RC6.10 (peeled cf2f499).

v3.1.1-RC6.10

Toggle v3.1.1-RC6.10's commit message
v3.1.1-RC6.10 — Refactor: extract SsrfGuard shared utility + source-t…

…ree NUL pre-commit scan

Refactor + tooling RC. No new SSRF gap closed; classifier behaviour
byte-equivalent.

- New jp.aegif.nemaki.security.SsrfGuard utility class — extracted
  from RC6.5/6.6/6.7-duplicated copies in HttpWebhookDispatcher and
  AdapterHttpClient. Both call sites delegate.
- New SsrfGuardTest — 30 direct cases.
- New Phase 1.4.1 source-tree NUL scan in scripts/validate-soc-templates.sh
  (1680 source files / 0 hits at HEAD).
- R3 follow-up (other-orchestrator audit) closed documentation-only:
  Mattermost + Salesforce RC6.8-protected; 8 others use hardcoded
  vendor URLs.

Tests: SsrfGuardTest 30/30 + HttpWebhookDispatcherTest 59/59 +
AdapterRegistryTest 26/26 + 7 adapter contract 76/76 = focused
24-class regression 373/373 PASS (was 343 in RC6.9; +30).

Base: v3.1.1-RC6.9 (peeled 76695f4).

v3.1.1-RC6.9

Toggle v3.1.1-RC6.9's commit message
NemakiWare v3.1.1-RC6.9 — Security: HTTP IP-pin preserves original Ho…

…st header + Javadoc honesty

Fifth RC in the SSRF hardening cycle. RC6.8 post-tag review raised
two findings to Medium; this RC closes the P3 compat caveat in
code and aligns the Javadoc with the post-RC6.8 doc-only P2 honesty
fix.

P3 fix — HTTP IP-pin preserves original Host header
  Before: pinRequestToValidatedAddress rewrote URI to validated IP
  literal and let JDK default Host header to that IP literal.
  Shared-vhost reverse proxies (one IP serving multiple Mattermost /
  Salesforce on-prem instances under different hostnames) would
  misroute / 404 because Host=IP doesn't match any vhost.

  After: rewrite URI to IP literal AND explicitly
  b.header("Host", originalHostHeader). Uses the documented JDK
  escape hatch:
    - JVM property -Djdk.httpclient.allowRestrictedHeaders=host
      added to docker/core/Dockerfile{,.jakarta,.simple}
      (CATALINA_OPTS / JAVA_OPTS) and core/pom.xml surefire argLine.
    - Defensive fallback: static {} initializer in AdapterHttpClient
      sets the property additively at class-load time.

  JVM-wide effect: other code in the same JVM that uses
  HttpRequest.Builder.header("Host", ...) will now succeed where it
  previously threw IllegalArgumentException. Intentional per JDK's
  documented escape hatch; no other call site in the codebase sets
  Host via the JDK HttpClient API.

Javadoc honesty alignment
  AdapterHttpClient.pinRequestToValidatedAddress Javadoc now
  reflects the actual security boundary (mirroring d910820 doc
  fix):
    - HTTP: "DNS rebinding closed at the network layer" — IP-pin
      prevents any TCP connection to a rebound IP. Host header
      preservation noted.
    - HTTPS: "TLS-bounded, NOT fully closed" — re-validation
      catches pre-resolve rebinds but a microsecond race remains;
      TLS cert verification stops data-exchange SSRF but
      TCP-connect SSRF (port-scan / fingerprint / TCP-side-effects)
      is residual. Real fix queued: custom SocketFactory pinning
      IP at TCP-connect time.

Tests:
  - 2 new pin Host-preserve regression tests in AdapterRegistryTest.
  - 7 adapter contract tests (Slack/Teams/Mattermost/Notion/
    Salesforce/M365/Chatwork) = 76 PASS unchanged.
  - HttpWebhookDispatcherTest 59 + AdapterRegistryTest 26 = 85
    PASS for SSRF surface.
  - Full focused regression: 343/343 PASS (was 265 in RC6.8;
    +78 from adding all 7 adapter contract test classes to the
    focused regression set + 2 new Host-preserve tests).

Java + TypeScript surface: byte-equal vs v3.1.1-RC6.8 except for:
  - AdapterHttpClient.java (+76 LOC)
  - AdapterRegistryTest.java (+31 LOC)
  - core/pom.xml (1 line in surefire argLine)
  - docker/core/Dockerfile{,.jakarta,.simple} (1 property each)

No API contract change. Behavioural changes:
  - HTTP pinned requests now send Host: original (was IP literal).
  - JVM-wide allowRestrictedHeaders=host effect documented above.

Remaining residual: HTTPS DNS pinning via custom SocketFactory
(carry-forward Medium residual from RC6.8). See REVIEW_PACKET §6.

See REVIEW_PACKET.md §2 for executive summary,
RELEASE_NOTES.md "3.1.1-RC6.9" for release-notes detail, CLAUDE.md
RC33/RC6.9 entry for project-internal navigation.

v3.1.1-RC6.8

Toggle v3.1.1-RC6.8's commit message
NemakiWare v3.1.1-RC6.8 — Security deeper closure: DNS rebinding pin …

…+ runtime endpoint revalidation + multi-hop redirect resolve in AdapterHttpClient

Fourth RC in the SSRF hardening cycle. RC6.5 closed the externally-
reported GHSA in HttpWebhookDispatcher (IPv6 transition unwrap).
RC6.6 hardened with IPv4 special-use + Teredo + RFC 6052 §2.2 /48
NAT64. RC6.7 horizontally extended the same closure to
AdapterHttpClient + flipped SHARED HttpClient redirect to NEVER.

RC6.8 closes 3 deeper gaps in AdapterHttpClient identified by a
deeper adversarial pass on the RC6.7 fix.

P1 — DNS rebinding gap
  validateExternalUrl resolved + validated once at config time,
  but sendWithRetry handed the original HttpRequest to
  HttpClient.send which performs its OWN DNS lookup. Attacker
  controlling the host's DNS could return public IP at validation
  and private/loopback/metadata IP at connection time.

  Fix: new pinRequestToValidatedAddress(request) called in both
  sendWithRetry and sendWithRedirectValidation:
  - HTTP: re-resolves at send time, validates every resolved
    address, rewrites URI to pinned IP literal (bracketed for IPv6).
    Host header sent as IP literal (JDK default restriction; most
    connector APIs respond to any Host).
  - HTTPS: returns request unchanged; TLS cert verification on
    original hostname handles rebinding. Re-validation still
    happens as belt-and-suspenders.
  - Unresolvable host throws SecurityException (behaviour change).

P2 — Runtime endpoint revalidation
  ConnectorDefinitionServiceImpl validates on save, but
  MattermostFetchOrchestrator (line 42) and
  SalesforceFetchOrchestrator (line 45) passed
  connector.getEndpoint() to adapters without revalidation.

  Fix: explicit AdapterHttpClient.validateExternalUrl(
  connector.getEndpoint()) at both orchestrator entry points.
  Defence-in-depth; P1 already closes the actual gap.

P3 — Multi-hop relative redirect resolve correctness
  sendWithRedirectValidation called request.uri().resolve(location)
  on every iteration but request was never updated.

  Fix: track currentRequest through the loop; use
  currentRequest.uri().resolve(location).

Tests:
  - 5 new pinRequestToValidatedAddress regression tests in
    AdapterRegistryTest (HTTP URI rewrite, HTTPS unchanged,
    SecurityException on rebound loopback/transition, header
    preservation).
  - 3 adapter test classes (Notion / Salesforce / Mattermost)
    add nemaki.ingest.allowLocalhost=true setUp/tearDown so
    WireMock localhost endpoints pass the new send-time
    revalidation.
  - HttpWebhookDispatcherTest 59 + AdapterRegistryTest 24 = 83
    PASS for SSRF surface.
  - 7 adapter contract tests (Slack/Teams/Mattermost/Notion/
    Salesforce/M365/Chatwork) = 71 PASS — pinRequest doesn't
    break legitimate adapter patterns.
  - Full 16-class focused regression: 265/265 PASS.

Java + TypeScript surface: byte-equal vs v3.1.1-RC6.7 except for
AdapterHttpClient.java + 2 orchestrators + AdapterRegistryTest +
3 test infra updates. No API contract change.

Out-of-scope (carry-forward from RC6.7):
  - Purview / Atlas / OIDC discovery / Microsoft Graph download
    outbound surfaces.

See REVIEW_PACKET.md §2 for executive summary,
RELEASE_NOTES.md "3.1.1-RC6.8" for release-notes detail, CLAUDE.md
RC32/RC6.8 entry for project-internal navigation, and the GHSA
advisory thread for reporter context.

v3.1.1-RC6.7

Toggle v3.1.1-RC6.7's commit message
NemakiWare v3.1.1-RC6.7 — Security: horizontal SSRF fix in AdapterHtt…

…pClient (all 11 connectors) + redirect tightening + test NUL cleanup

Third RC in the SSRF hardening cycle.

RC6.5 closed the externally-reported GHSA from tonghuaroot in
HttpWebhookDispatcher (IPv6 transition address unwrap).
RC6.6 hardened HttpWebhookDispatcher with 5 IPv4 special-use ranges,
Teredo 2001::/32, and proper RFC 6052 §2.2 /48 layout for the NAT64
local-use prefix.

RC6.7 horizontally extends the same closure to
AdapterHttpClient.validateExternalUrl, the shared outbound HTTP
validator used by:
  - All 11 external-ingest connector adapters (Slack / Teams /
    Mattermost / Notion / Salesforce / M365 Mail / Gmail / Chatwork /
    Box / Dropbox / IMAP)
  - ConnectorDefinitionServiceImpl (endpoint validation at config
    save time)
  - IngestWebhookController (notification callback URL validation)

Before RC6.7, validateExternalUrl only checked the JDK's
isLoopback / isLinkLocal / isSiteLocal / isAnyLocal predicates —
the same gap that allowed the RC6.5+RC6.6 bypass class through
HttpWebhookDispatcher. An attacker who could supply an adapter
endpoint URL (admin during connector setup, or via webhook scope /
redirect chain at runtime) could reach internal IPv4 via NAT64,
6to4, Teredo, IPv4-compatible, IPv4-mapped wraps, OR via IPv4
special-use ranges not classified by JDK predicates (0/8 beyond
0.0.0.0, 100.64/10 CGNAT, 192.0.0/24 IETF assignments, 198.18/15
benchmarking, 240/4 reserved + broadcast).

Fix: replicate the proven isAddressSafe + extractEmbeddedIpv4
design pattern from HttpWebhookDispatcher (in-place duplication;
extract-to-shared-helper tracked as follow-up tech debt).

Redirect handling tightened:
  - SHARED HttpClient: Redirect.NORMAL → NEVER. JDK auto-follow
    without revalidating target is a known SSRF anti-pattern.
  - sendWithRedirectValidation: relative Location headers
    (e.g. "Location: /admin") now resolve against the original
    request URI before validateExternalUrl. Previously the
    relative form would either fail URL parsing or be
    misinterpreted.

Test source NUL cleanup:
  - HttpWebhookDispatcherTest.java line 481 had literal 0x00 NUL
    in "with\x00nul"; replaced with Java \0 octal escape. .class
    is byte-equivalent (compiler resolves \0 to same NUL byte).
    Source file no longer classified as binary by grep / rg / file.

Tests:
  - 3 new regression tests in AdapterRegistryTest covering IPv6
    transition wraps (5 forms), IPv4 special-use ranges (3 reps),
    SHARED HttpClient redirect setting.
  - HttpWebhookDispatcherTest 59 + AdapterRegistryTest 19 = 78 PASS
    for SSRF surface.
  - 6 connector adapter contract tests (Slack/Teams/Mattermost/
    Notion/Salesforce/M365) = 63 PASS — confirms Redirect.NEVER
    does NOT break legitimate adapter patterns.
  - Full 16-class focused regression: 260/260 PASS.

Java + TypeScript surface: byte-equal vs v3.1.1-RC6.6 except for
AdapterHttpClient.java + its test + the test source NUL cleanup.
No API contract change.

Out-of-scope: Purview / Atlas / OIDC discovery / Microsoft Graph
download outbound — admin-configured IdP / on-prem endpoint use
cases would break under unconditional blocklist. Future opt-in
production-mode or explicit allowlist.

See REVIEW_PACKET.md §2 for executive summary, RELEASE_NOTES.md
"3.1.1-RC6.7" for release-notes detail, CLAUDE.md RC31/RC6.7 entry
for project-internal navigation, and the GHSA advisory thread for
reporter context.

v3.1.1-RC6.6

Toggle v3.1.1-RC6.6's commit message
NemakiWare v3.1.1-RC6.6 — Security hardening follow-on: SSRF guard ad…

…ds IPv4 special-use ranges + Teredo + RFC 6052 /48 NAT64

Follow-on security RC on top of v3.1.1-RC6.5. RC6.5 closed the
externally-reported GHSA (IPv6 transition addresses unwrap).
RC6.6 closes additional bypass surfaces an attacker could pivot
to once the obvious RC6.5 holes were closed, identified via an
adversarial pass on the RC6.5 fix:

5 IPv4 special-use ranges added to isAddressSafe:
  - 0.0.0.0/8        ("this" network beyond literal 0.0.0.0, RFC 1122)
  - 100.64.0.0/10    (carrier-grade NAT, RFC 6598)
  - 192.0.0.0/24     (IETF protocol assignments, RFC 6890)
  - 198.18.0.0/15    (benchmarking, RFC 2544)
  - 240.0.0.0/4 + 255.255.255.255 (reserved + broadcast, RFC 1112)

2 IPv6 transition formats added to extractEmbeddedIpv4:
  - 64:ff9b:1::/48   (NAT64 local-use RFC 8215, with RFC 6052 §2.2
                     /48 byte layout: IPv4 in bytes 6-7 + 9-10,
                     skipping byte 8 = "u" octet, suffix bytes
                     11-15 must be zero; fallback to /96-PLR
                     extraction when suffix is non-zero).
  - 2001::/32        (Teredo RFC 4380, strict prefix check so
                     other 2001::/16 addresses are not
                     mis-extracted; client IPv4 stored as one's
                     complement in bytes 12-15).

Tests: HttpWebhookDispatcherTest 59/59 PASS (52 from RC6.5 + 7
new test methods + 2 inline assertions in the existing extractor
test). New test coverage: 3 IPv4 special-use blocks (100.64 /
198.18 / 240/4), 2 RFC 6052 /48 NAT64 (loopback wrap blocked,
8.8.8.8 wrap allowed), 2 Teredo (one's complement of ffff:fffe =
0.0.0.1 wrap blocked, f7f7:f7f7 = 8.8.8.8 wrap allowed).

Java + TypeScript surface: byte-equal vs v3.1.1-RC6.5 except for
HttpWebhookDispatcher.java (hardening) + its test (+134 / -14
LOC). No API contract change.

Residual: HTTPS dispatch still uses the original hostname URL to
leverage TLS certificate validation (DNS rebinding mitigated by
TLS verification) — by design, unchanged from prior RCs.

See REVIEW_PACKET.md §2 for the executive summary,
RELEASE_NOTES.md "3.1.1-RC6.6" for release-notes detail, and
CLAUDE.md RC30/RC6.6 entry for the project-internal navigation.

v3.1.1-RC6.5

Toggle v3.1.1-RC6.5's commit message
NemakiWare v3.1.1-RC6.5 — Security: SSRF guard unwraps IPv6 transitio…

…n addresses + connector manual-verification doc closure

Focused security RC in the 3.1.1 line. Two pieces:

GHSA SSRF fix (CWE-918) — HttpWebhookDispatcher.isAddressSafe now
extracts embedded IPv4 from IPv6 transition formats and recursively
re-classifies it, closing a reporter-supplied bypass where internal
IPv4 destinations (loopback, RFC 1918, link-local 169.254 incl.
cloud metadata) wrapped as NAT64 64:ff9b::/96 + 64:ff9b:1::/48,
6to4 2002::/16, or IPv4-compatible ::a.b.c.d literals slipped past
the existing guard on dual-stack / NAT64 networks. 15 regression
tests added (HttpWebhookDispatcherTest 52/52 PASS). Reported by
tonghuaroot via GitHub security advisory.

Connector-area manual-verification doc closure — docs/MANUAL-
VERIFICATION-CONNECTORS.md went through 3 rounds of external review
with live execution by the reviewer. 15 external findings + 9
self-review findings = 24 fixes, all live-verified against the
deployed RC6 HEAD stack. Every documented HTTP code and message
snippet now matches actual server behaviour; the "X or Y" vague
expect-value pattern is fully eliminated. §14 documents the
addACEPrincipal[n] silent no-op trap and the defaultConnectorId
uniqueness constraint as future-trap warnings.

Java + TypeScript surface: byte-equal vs v3.1.1-RC6.4 except for
HttpWebhookDispatcher.java (security fix) + its test. No API
contract change.

See REVIEW_PACKET.md §2 for the executive summary, RELEASE_NOTES.md
"3.1.1-RC6.5" for release-notes detail, CLAUDE.md RC29/RC6.5 entry
for the project-internal navigation, and the GHSA advisory at
github.com/aegif/NemakiWare/security/advisories for the reporter
context.