PlantUML information leakage and compliance — source/diagram bidirectional exposure risks

puml.online

PlantUML diagrams carry both source and rendered output — two-way exposure = two-way leakage. Most teams don’t realise diagrams are a reverse data source for compliance, security, and AI training. This post inventories the risks, mitigation recipes, and compliance strategy.

Diagrams leak more easily than prose

Why they’re more dangerous

A blog post: “We use 192.168.1.10 as the PostgreSQL primary.” Text leakage only happens if the author makes a mistake.

But a PlantUML diagram:

1
2
3
4
5
6
7
8
9
10
package "Production" {
[Frontend] as fe
[PostgreSQL] as pg
[Redis] as rd
[Auth Service] as auth
}

fe --> pg : "jdbc:postgresql://10.0.5.20:5432/dbname"
pg <-> rd
fe --> auth

The author doesn’t even need to type the IP — it can be auto-imported from infra-as-code or scraped from service registry. Source code scrapes, when leaked, expose all the context (hostnames + ports + relationships) in one place — the analyst reading the diagram already has the architecture without needing access.

Worse: PlantUML supports !include to bring in files. A !include ../internal-infra/architecture.puml in your public repo literally publishes internal network topology on the public web.

Five common leak categories

1. Internal IPs / hostnames

1
2
node "10.0.5.20" as db1
node "10.0.6.30" as web1

A diagram rendered on the public site leaks all internal IPs at once. Worse, post-mortem reports that import from internal conf records often paste full topology into a puml file.

2. Credentials / access tokens

1
2
3
note right of auth
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
end note

Notes accidentally pasted with production auth tokens.

Or:

1
' redis://redis:abc123@redis-prod.cache.amazonaws.com:6379

Password hash leaked via a comment.

3. Internal API endpoints

1
web1 --> api1 : "POST https://api.internal-payments.corp.svc.cluster.local/pay"

Full URL exposure — service catalog AND version path AND authentication bypass.

4. Business-context topology

Even without specific names, the relationship itself is sensitive:

  • 业务 1 依赖 业务 2 的下单服务 —— 竞品分析
  • 收购/合并讨论期间的组织架构图
  • 薪资系统与某些产品经理的耦合关系(暴露 PM 离职/调岗)

「The fact that services X and Y are linked, even without explicit names, is enough to reconstruct the corporate structure.」

5. Real customer / partner names

1
2
"Account A 客户名" as a
a --> "ON THE WAY 协议" as b

Names of enterprise customers appear in the diagram as captions — these are NDAs.

Self-audit compliance checklist

Imagine your company is going through a SOC2 audit. Review the PlantUML diagram files:

1
2
3
4
5
6
7
8
9
10
# Audit script
#!/bin/bash
echo "→ Scanning for IPs"
grep -rE '\b[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\b' docs/diagrams/

echo "→ Scanning for internal domains"
grep -rE '\.internal|\.corp|\.svc\.cluster\.local' docs/diagrams/

echo "→ Scanning for sensitive annotations"
grep -riE 'bearer\s+[A-Za-z0-9]|secret=|password=' docs/diagrams/

If anything matches, redact before publishing.

Five mitigation recipes

Recipe 1: alias replacement (default)

1
2
3
4
5
node "PostgreSQL Primary" as p1
node "Redis" as r1
node "Auth Service" as auth

web1 --> p1 : "jdbc:postgresql://10.0.5.20"

Becomes:

1
2
3
4
5
node "Database Tier" as p1
node "Cache Tier" as r1
node "Auth Service" as auth

web1 --> p1 : "TCP 5432"

Replace concrete names with abstract tiers. Reserve full names for internal-only diagram sets.

Recipe 2: pre-processing script

1
2
3
# /scripts/sanitise-puml.sh
sed -E 's|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}|XXX.XXX.XXX.XXX|g' \
input.puml > output.puml

CI pipeline runs this before publishing.

Recipe 3: scanning gate

1
2
3
# CI step: reject PRs with raw IPs
! grep -rE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' docs/diagrams/ \
&& grep -qE 'docs/diagrams/*.puml'

CI fails on raw IP → author must use aliases.

Recipe 4: alias-map.json (canonical)

1
2
3
4
5
{
"10.0.5.20": "DB-PRIMARY",
"redis-prod.cache.amazonaws.com": "CACHE",
"auth.internal-payments.corp.svc.cluster.local": "AUTH"
}

CI replaces via this map before rendering the public image. External diagrams use generic names. Internal diagrams use full names. Two pipelines, one source.

Recipe 5: don’t publish source

  • *.puml is a private repo
  • The publicly-shared version is only rendered SVG
  • A nightly job: plantuml -tsvg *.puml -o public/diagrams/ (only SVG to public)
  • CI gated: a pre-commit check forbids !include ../private-architecture.puml in public puml files

plantuml.com vs self-host — security differences

plantuml.com is risky

https://www.plantuml.com/plantuml/svg/~1<encoded> has issues:

  • Server access logs — rendered puml source enters the log
  • Log retention unclear — a leaked puml might resurface 6 months later
  • Cross-border transit — source goes through foreign ISPs / CDNs

For companies with GDPR / SOC2 / HIPAA, plantuml.com is typically banned.

Self-host via Docker

1
docker run -d -p 8080:8080 plantuml/plantuml-server

Source stays on your network. Log retention is under your control.

Note: even self-hosting has logs. If plantuml-server puts INFO PlantUML request in journald, you still have audit trail of rendered source. Decide retention explicitly.

TeaVM client-side = zero logs

puml.online uses client-side WASM rendering — source never leaves the browser. The TeaVM compiled plantuml.js runs in your browser, no server. Logs are only yours to keep (DevTools console).

AI training data reverse-leakage (2026 new worry)

The problem

If your diagram ends up on github.com publicly (or in a public wiki), it gets crawled by:

  • OpenAI for training data
  • Anthropic for training data
  • Google for training data
  • random fine-tuning datasets

Risk vectors:

  1. Architecture disclosure — LLM can reconstruct details from context.
  2. Indirect corporate structure inference — even if names are aliases, the topology itself is sensitive.
  3. Customer name leakage — the data layout exposes partnership relationships.

Mitigation

  • !include 注释 + CI check disallowing public !include ../private-architecture.puml
  • puml source only in private repo + sanitised SVG to public
  • On discovery of leaked public diagrams: git filter-repo + force push to rewrite history

Are LLMs legally allowed to train on your diagrams?

Consult each company’s “public material collection” policy. Most companies:

  • Employee public repo commits are deemed company assets (unless contracts say otherwise)
  • Public = consented to crawls = used for training

Important strategy: write an explicit “*.puml not allowed in public repos” corporate policy (CLA).

Toolchain security audit

If you have 100+ PlantUML files, audit periodically:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
# scripts/audit-puml-leaks.sh
# Check for sensitive info in puml sources
echo "→ scanning IPs"
grep -rE "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" docs/diagrams/ && {
echo "❌ IPs found"
exit 1
}

echo "→ scanning internal domains"
grep -rE "\.internal|\.svc\.cluster\.local|\.corp" docs/diagrams/ && {
echo "❌ internal domains found"
exit 1
}

echo "→ scanning credentials"
grep -riE "password=|api_key=|secret=|token=" docs/diagrams/ && {
echo "❌ credentials found"
exit 1
}

echo "✓ passed"

Integrate into CI: every PR runs automatically.

Public vs private dual-track case

Our puml.online publish strategy:

Content Repo Encoding Rendered output
Tutorial examples public alias + simplified SVG
Company production internal private full names + real SVG (internal access)
Internal audit internal private full names SVG (internal access)

Rendering pipeline:

1
2
3
4
5
6
7
8
9
10
Developer edits puml

CI validates syntax

Render SVG (multiple alias modes):
- public version: alias replacement + simplified
- internal version: full names preserved

public version → gitee push
internal version → internal CDN

AI-era additional defences

1. Inject anti-crawler markers

1
2
' This diagram contains commercially-sensitive information, 
' crawling without authorisation is prohibited.

Text annotations are noise to crawlers — LLM training will ignore or weight negatively.

2. Alias hashing

1
2
def hash_alias(hostname):
return hashlib.sha256(hostname.encode()).hexdigest()[:8]

Maps db1.company.internal9f3b2c4d. LLMs can’t link these to real hostnames during training.

3. “Wrong names” misdirection

Deliberately put wrong service names in the diagram — attackers’ data harvest still has real but value-less names.

Landing checklist

Audit quarterly:

  • Are your company’s PlantUML sources in public repos?
  • Do GitHub README-embedded diagrams contain internal info?
  • Does the repo README have a “corporate policy” header declaring puml sources not for public?
  • Does the PR template require sanitisation before PR?
  • Does CI auto-scan IPs, domains, credential strings?
  • Have team members been taught “diagrams leak more than text”?
  • Are public render results (SVG) sanitised a second time?
  • Is cross-border plantuml.com disabled?

puml.online’s own practice

We:

  • Tutorial example diagrams use aliases (AuthService, OrderService, no IP/port)
  • Source open (tutorial angle)
  • Client-side rendering (TeaVM: source never leaves the browser)
  • No server in CI — pure static + client-side
  • Don’t use plantuml.com online service

Recap

  • PlantUML diagrams leak more than text — “two-way exposure” is the core issue
  • 5 risk categories: IP / credentials / URLs / context / customer names
  • 5 recipes: alias / replace / scan / map / no-publish
  • The 2026 new pitfall: AI training-data reverse-leakage risk
  • Public-domain vs self-host vs TeaVM: security order TeaVM > self-host > plantuml.com

Next

  • Title: PlantUML information leakage and compliance — source/diagram bidirectional exposure risks
  • Author: puml.online
  • Created at : 2026-07-30 12:46:00
  • Updated at : 2026-08-14 21:34:29
  • Link: https://puml.online/blog/plantuml-security-leak-en/
  • License: This work is licensed under CC BY-NC-SA 4.0.