- Add privacy projection (core/privacy.py), private report storage, bounded
process capture; omit identities, free text and unapproved paths
- Mask remote peer IPs: only loopback/host/wildcard stay numeric, others are
reduced to remote_scope private/public (schema + scoring updated)
- Map ss TCP states to canonical names; ASCII-only numeric fields; fix
"Microsoft Visual C++" product matching (Python and PowerShell)
- Merge 7fed3b9: -Diagnostic switch, serialization exit code 3, PS7 module
path, UI error detail; keep hardened task/certificate collectors
- Add audit docs, privacy docs and regression tests
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
203 lines
12 KiB
Markdown
203 lines
12 KiB
Markdown
# Privacy hardening and production acceptance
|
|
|
|
This document describes implemented controls, not a HIPAA compliance determination.
|
|
The documents in `audit/` remain the historical audit of the earlier source snapshot.
|
|
Do not replace their findings with an unsupported claim that all issues are resolved.
|
|
|
|
## What changed
|
|
|
|
- A new `core/privacy.py` builds an explicit field projection before results reach Qt,
|
|
analysis/history, imports, HTML, JSON, and local CLI output. Export recomputes
|
|
findings from minimized inventory; old findings and a privacy marker cannot bypass
|
|
the filter. Unexpected schema fields are rejected at import; legacy command fields
|
|
are accepted only to discard them. Timestamps are checked without optional plugins.
|
|
- Host/domain/adapter identities, accounts, display descriptions, custom service,
|
|
software and task names, certificate identities and unapproved paths are omitted
|
|
or replaced with assessment-local numbered labels. Known application families,
|
|
OS family/version/build, role identifiers, states, PIDs, ports, numeric IPs,
|
|
storage capacities, row counts, timestamps and categorical errors remain useful.
|
|
Unknown software is not automatically interpreted as inactive or harmless.
|
|
- Windows queries no longer request service account/display-name fields. Task CIM
|
|
queries request only TaskName, TaskPath and State; actions, arguments, principals,
|
|
triggers and task XML are not requested. Disk queries omit volume labels.
|
|
Registry reads disable environment expansion and omit publisher/install-date text.
|
|
The PowerShell modules project names and paths before emitting JSON.
|
|
- Certificate enumeration and SMB open-file/session enumeration are disabled.
|
|
Certificates are explicitly `not_collected`; tasks, storage and shares have
|
|
partial scope. Share consumers and schedule timing must be verified separately.
|
|
Existing imported aggregate share counts can still support a finding, but their
|
|
provenance is unverified. They do not cause the new collector to enumerate files.
|
|
- Linux default collection no longer reads cron command files or detailed systemd
|
|
timer properties. Timer state remains available; commands and timings need a
|
|
separate approved scheduler review. Existing schedule parsers are retained for
|
|
synthetic tests, but are not called by the default collection workflow.
|
|
- Supervised collector stdout uses bounded memory pipes instead of inventory
|
|
temporary files. Stderr is discarded. Windows child environment has an explicit
|
|
small allowlist instead of copying all environment variables. Timeouts,
|
|
cancellation and overflow terminate/reap the owned process.
|
|
- Reports contain minimized data only. HTML does not create raw sidecars. Output
|
|
is exclusive (no overwrite), restricted to the configured local report root, and
|
|
checks common network mounts, symlinks and Windows reparse points. POSIX root
|
|
mode is 0700 and files 0600. Windows roots require a protected DACL allowing only
|
|
the owner, SYSTEM and Administrators; child ACLs are checked before payload write.
|
|
No automatic privilege elevation or existing ACL changes are performed.
|
|
- History retains at most ten assessments by default, and has a clear action.
|
|
Clearing references is not secure memory erasure. Existing exported files are not
|
|
automatically deleted. Scoring-policy titles are canonicalized to prevent a
|
|
second free-text report channel.
|
|
- Requirements now use the Widgets-capable `PySide6_Essentials`, rather than the
|
|
umbrella package that pulls in WebEngine, PDF and Addons. Direct versions are
|
|
pinned; observed development transitive constraints are recorded separately.
|
|
|
|
- Remote peer IP addresses are masked: only loopback, this host's own and wildcard
|
|
addresses stay numeric; every other peer is reduced to `remote_scope` `private` or
|
|
`public`, because client IPs on patient-facing servers can be identifiers. Local
|
|
listener addresses and the host's own IPs are still retained.
|
|
|
|
## Configure approved metadata and report storage
|
|
|
|
Deployment administrators review and protect these bundled files against untrusted
|
|
changes: `samsara/assets/privacy_policy.json` and `privacy_catalogue.json`. The
|
|
catalogue is a finite vocabulary of infrastructure names, not executable code.
|
|
Keep the checkout, Python environment and scripts protected by deployment controls.
|
|
An attacker who can replace application code/policy is outside this boundary.
|
|
|
|
The policy defaults to no approved names/paths and an application-local `reports`
|
|
folder. This is a laboratory default, not a CHS-approved production location. Set
|
|
`report_directory` to an approved **absolute local** directory for deployment.
|
|
Only files directly inside it can be saved; choose a new `.html` or `.json` filename.
|
|
Do not put the directory under OneDrive, another sync client, a network mount or an
|
|
unreviewed backup policy. Encrypted local storage and access/retention policy remain
|
|
organizational requirements.
|
|
|
|
For example, a reviewed Windows configuration may include:
|
|
|
|
```json
|
|
{
|
|
"version": "1.0",
|
|
"report_directory": "C:\\SamsaraReports",
|
|
"approved_hostnames": [],
|
|
"approved_share_roots": ["D:\\DepartmentShares"],
|
|
"approved_service_names": [],
|
|
"approved_software_names": [],
|
|
"max_session_assessments": 10
|
|
}
|
|
```
|
|
|
|
This preserves **only the exact configured root** `D:\DepartmentShares`. It does
|
|
not authorize any child path, filename or file-content scan. Empty allowlists are
|
|
preferred. Add an exact hostname/custom service/software name only after privacy
|
|
review establishes it is approved infrastructure metadata. There is no automatic
|
|
patient-name detector: neither a path nor a free-text name can be proven safe from
|
|
its format. Known product names are canonicalized without retaining custom suffixes.
|
|
|
|
On Linux, the configured root is created with mode 0700 if its parent already
|
|
exists. An existing root with group/other permissions is rejected. Fix permissions
|
|
on the report directory only after checking that it is the intended directory.
|
|
|
|
On Windows, provision a **new** local folder before exporting. The following is a
|
|
manual setup example to be reviewed under the organization's normal approval
|
|
process, not an action the collector performs on assessed infrastructure:
|
|
|
|
```powershell
|
|
$reportRoot = 'C:\SamsaraReports'
|
|
if (Test-Path -LiteralPath $reportRoot) { throw 'Choose a new report directory.' }
|
|
$null = New-Item -ItemType Directory -Path $reportRoot
|
|
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
try {
|
|
$acl = New-Object Security.AccessControl.DirectorySecurity
|
|
$acl.SetOwner($identity.User)
|
|
$acl.SetAccessRuleProtection($true, $false)
|
|
foreach ($sid in @($identity.User, [Security.Principal.SecurityIdentifier]::new('S-1-5-18'), [Security.Principal.SecurityIdentifier]::new('S-1-5-32-544'))) {
|
|
$rule = [Security.AccessControl.FileSystemAccessRule]::new($sid, 'FullControl', 'ContainerInherit,ObjectInherit', 'None', 'Allow')
|
|
$acl.AddAccessRule($rule)
|
|
}
|
|
Set-Acl -LiteralPath $reportRoot -AclObject $acl
|
|
} finally { $identity.Dispose() }
|
|
```
|
|
|
|
These commands change the chosen **local output folder's** ACL and must not be run
|
|
against data shares. Configure the matching path in the policy. The ctypes ACL
|
|
reader and inheritance behavior are implemented but **not tested on Windows here**.
|
|
Before production, verify both allowed and denied cases, inherited file ACLs,
|
|
standard-user access, reparse/mapped-drive rejection and directory replacement
|
|
races on each intended Windows execution environment. Export fails closed when it
|
|
cannot establish the configured checks; absence of an exception is not a complete
|
|
filesystem-security attestation.
|
|
|
|
## Limits and unresolved production blockers
|
|
|
|
1. **No PHI-free guarantee.** Names/paths returned by CIM, Get-SmbShare, process
|
|
listings and registry values can enter collector memory before reduction.
|
|
Legacy JSON is parsed in memory before filtering. Explicit properties reduce
|
|
requested fields but provider internals are unverified. Approved names/roots
|
|
and retained numeric IPs can themselves be sensitive in organizational context.
|
|
2. **No absolute read-only OS guarantee.** Application collection commands request
|
|
reads, not infrastructure changes. Native providers/OS can write audit logs,
|
|
caches or other incidental state. Python bytecode, OS paging/crash dumps, Qt and
|
|
endpoint tools are outside the no-inventory-spool control. A bounded buffer is
|
|
not secure memory. Disable/restrict crash dumps and use encrypted storage under
|
|
organizational policy, rather than claiming that data never touch disk.
|
|
3. **No complete egress guarantee.** There is no first-party upload, telemetry or
|
|
remote collector. Filesystem checks reject common remote paths but cannot prove
|
|
a disk has no cloud-sync/backup/virtualized backend. Native Windows providers,
|
|
revocation behavior, domain services and OS integrations need monitored host
|
|
validation. Use enterprise egress policy and approved local output storage.
|
|
4. **Runtime validation outstanding.** No Windows execution host or PowerShell
|
|
runtime was available. Revised CIM projections, least-privilege visibility,
|
|
native synthetic tests and output ACL enforcement must pass on approved lab
|
|
hosts. Do not substitute synthetic Python results for that evidence.
|
|
5. **Supply chain approval outstanding.** No vulnerability database queries,
|
|
package installations/updates or external transmissions were performed. Direct
|
|
pins/observed constraints are not a hash-verified platform lockfile, complete
|
|
native SBOM, signed release or CVE clearance. Existing development environments
|
|
may still contain the former Qt umbrella/Addons packages; changing requirements
|
|
does not uninstall them. Build clean environments through approved provisioning.
|
|
6. **Organizational review outstanding.** CHS security/privacy approval, least-
|
|
privilege grants, retention/deletion policy, approved metadata, endpoint and
|
|
backup controls, incident response and HIPAA determination remain external
|
|
acceptance gates. A low retirement score always needs historical validation,
|
|
application ownership and administrator approval.
|
|
|
|
Do not import known patient-bearing legacy inventories into this tool merely to
|
|
redact them. Have the data owner handle those artifacts using approved procedures.
|
|
Old reports/sidecars/bundles are not scrubbed or removed by this change. The
|
|
historical `Samsara.bundle`, if present, may predate these controls; distribute a
|
|
reviewed build of the current source rather than an older archive.
|
|
|
|
## Verification and later authorized supply-chain checks
|
|
|
|
Run synthetic/offscreen tests from the repository root:
|
|
|
|
```bash
|
|
QT_QPA_PLATFORM=offscreen .venv/bin/python -m unittest discover -s tests -v
|
|
```
|
|
|
|
On an authorized Windows **lab** Server with an approved report directory:
|
|
|
|
```bat
|
|
.venv\Scripts\python.exe -m unittest discover -s tests -v
|
|
.venv\Scripts\python.exe tools\validate_windows_host.py --output-dir C:\SamsaraReports
|
|
```
|
|
|
|
The second command performs a real assessment of the execution host; it is not a
|
|
synthetic test. No real Windows host has been assessed during this change.
|
|
|
|
After obtaining approval for tooling/downloads and advisory-database access, in a
|
|
separate release environment use, for example:
|
|
|
|
```bash
|
|
python -m piptools compile --generate-hashes --output-file requirements.lock requirements.txt
|
|
python -m pip install --require-hashes -r requirements.lock
|
|
python -m pip_audit -r requirements.lock --format json --output vulnerability-results.json
|
|
cyclonedx-py environment --output-format JSON --output-file sbom.cdx.json
|
|
```
|
|
|
|
Repeat lock generation/clean installs for each target Python/OS/architecture.
|
|
Inventory Qt native libraries/plugins and PowerShell/OS modules as well; a Python
|
|
package SBOM alone is incomplete. SBOM/advisory checks can expose package metadata
|
|
externally: do not run them against production inventory or without authorization.
|
|
Triage findings against actual packages, keep advisory timestamps, sign the
|
|
reviewed distribution, and retain acceptance evidence. These commands have not
|
|
been run as part of the hardening work.
|