Conversation
- Validate Import-from-JSON trees (reserved keys, identifiers, types, composition and condition-set references) before persisting; generic operator-facing error messages - Sanitize Notebook Markdown links and TextHighlight output against XSS - Normalize CouchDB / LocalStorage failures to a generic PersistenceError with raw details kept in console logging - Add an in-process AuditLogger service (openmct.audit) with hooks for import, export, role change, notebook entry create/delete, and fault acknowledge/shelve - Add docs/security/asd-stig-nist-800-53-review.md with findings and explicit per-boundary outcomes Co-Authored-By: Erik Rozi <erik.rozi@cognition.ai>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
Original prompt from Devin Bot
|
| /** | ||
| * Structured audit records (who / what / when / outcome) for operator | ||
| * actions. Providers subscribe to receive records; nothing is persisted | ||
| * or transmitted by default. | ||
| * @type {AuditLogger} | ||
| */ | ||
| this.audit = new AuditLogger(this); |
There was a problem hiding this comment.
Acknowledged. openmct.audit is a new public API and per CONTRIBUTING.md needs senior-developer approval before merge; this PR is intentionally left unmerged for that review. The API surface is small (record, addProvider, removeProvider, hasProviders, EventEmitter on/off/once) and documented in API.md.
…tions; bound import traversal; isolate audit provider failures Co-Authored-By: Erik Rozi <erik.rozi@cognition.ai>
Browser evidence: import validation, Notebook XSS sanitization, audit recordsDriven through the real UI at Annotated recording (2 min): security-browser-tests-edited.mp4 · full write-up: testing-report.md Scenarios
Findings from the browser run and their disposition
CI follow-ups in this push (887b66c)
|
Co-Authored-By: Erik Rozi <erik.rozi@cognition.ai>
There was a problem hiding this comment.
There is no tracking issue on this fork for this review; the work was requested directly, so "Closes N/A" is deliberate. If a tracking issue is opened I will link it in the description.
…guard localStorage getter; emit audit events via EventEmitter; document Audit API Co-Authored-By: Erik Rozi <erik.rozi@cognition.ai>
- ExportAsJSONAction: nested #exportObject writes are returned so a descendant load failure reaches the generic handler (dialog closes, generic notification, failure audit record) - Notebook createNewImageEmbed resolves undefined and notifies the operator on FileReader, thumbnail or persistence failure instead of staying pending; consumers skip undefined embeds - ImportFromJSONAction waits for every save to settle before reporting a failure and never links the root on partial failure - AuditLogger.record() resolves after asynchronous providers settle; provider rejections stay isolated; API.md documents the contract - importValidation documents why type keys are allowlisted and adds a spec pinning plugin-style type keys, namespaced identifiers and deep plugin configuration as accepted Co-Authored-By: Erik Rozi <erik.rozi@cognition.ai>
… import objects Co-Authored-By: Erik Rozi <erik.rozi@cognition.ai>
Co-Authored-By: Erik Rozi <erik.rozi@cognition.ai>
Co-Authored-By: Erik Rozi <erik.rozi@cognition.ai>
Closes N/A (security review; no linked issue)
Describe your changes:
Source-code review of Open MCT's untrusted-input and data boundaries against the DISA ASD STIG V6R4 (2025-09-09) and NIST SP 800-53 Rev. 5, plus remediation of the highest-value findings with Karma specs. The full assessment, including every boundary's explicit outcome and the deployment evidence an assessor would need, is in
docs/security/asd-stig-nist-800-53-review.md. This is a code review, not a certification or attestation of compliance.Findings already addressed by #10 (Comps
mathjs), #11 (Web Page iframe sandbox / URL allowlist), #12 (npm registry signatures) and #13 (CSV formula injection) are excluded and not duplicated.Findings table
Severity is the ASD STIG category of the cited rule. Line numbers refer to this branch.
importFromJSONAction/ImportFromJSONAction.js:87__proto__filter;constructor/prototypekeys, identifier/key mismatches, non-string types, bad composition/condition-set references and unknown roots acceptedImportFromJSONAction.js:106,452ImportFromJSONAction.js:348-350exportAsJSONAction/ExportAsJSONAction.js:102-107notebook/components/NotebookEntry.vue:460-479data:/protocol-relative links; link allowlist matched hostname suffixes; hand-built anchor did not escape text/hrefNotebookEntry.vue:571,NotebookComponent.vue:676,notebook-image.js:72persistence/couch/CouchObjectProvider.js:233-285fetch/CouchDB textlocalStorage/LocalStorageObjectProvider.js:37-105JSON.parseexceptions thrown raw to callersutils/textHighlight/TextHighlight.vue:24,63-65v-htmlmarkup unescaped and used as an unescaped regexinnerHTMLsites (listed in doc)formActions/CreateAction.js:94Error saving objects: ${err}shown to operatorui/layout/AboutDialog.vue:30v-htmlof deployerBranding.aboutHtml(configuration, not user data)UserAPI.js:135,FaultManagementAPI.js:122-171, import/export actions,notebook-entries.js:242-356,NotebookComponent.vue:586URLIndicatorPlugin/URLIndicator.js:78,100persistence/couch/plugin.js:36-68,CouchObjectProvider.js:218CouchObjectProvider.js:218example/exampleUser/ExampleUserProvider.js:96-240,userIndicator,operatorStatus,api/userLocalStorageObjectProvider.js,api/user/StoragePersistence.js:27-33localStorage; CouchDB at-rest is server-sideapi/audit/AuditLogger.jscondition/utils/operations.js:45,summaryWidget/src/ConditionEvaluator.js:344-413eval/new Functionhyperlink/HyperlinkLayout.vue:50hrefpassed through@braintree/sanitize-urlnotebook/components/NotebookEmbed.vue:31,notebook-image.js:srcfrom app-generated capturesNotebookEntry.vue:684api/objects/ObjectAPI.js:441Counts: 11 not-satisfied -> remediated; 7 satisfied; 7 needs-input; 1 not-applicable; 0 not-satisfied left open.
Remediated in this PR
importValidation.js(new): rejects__proto__/constructor/prototypeat any depth, validates root, identifier/key-string consistency, type/name/location, composition and condition-set references;ImportFromJSONActionvalidates the whole tree before the firstsave(), shows fixed messages, logs diagnostics, and emitsimportaudit recordsimportValidationSpec.js,ImportFromJSONActionSpec.jsNotebookEntry.vue:sanitize-htmlschema restricted tohttp/https/mailto, no protocol-relative URLs, enumerated attributes; link renderer requireshttp(s):, exact host or dot-delimited subdomain, escapes text and href, addsrel="noopener noreferrer".TextHighlight.vue: HTML- and regex-escaped term, escaped class,$1reinsertionNotebookEntrySpec.js(new),TextHighlightSpec.js(new)PersistenceError(new, exposed asopenmct.objects.errors.Persistence); Couch and LocalStorage providers normalize failures to it with raw details inconsole.error;Conflictpreserved; generic messages in export, notebook image andCreateActionpathscouch/pluginSpec.js,localStorage/pluginSpec.js,ExportAsJSONActionSpec.js,CreateActionSpec.jsAuditLogger(new) registered asopenmct.audit; records{id, source, timestamp, action, outcome, actor{id,username,role}, target, details}to subscribers viaaddProvider({ record }); hooks inUserAPI.setActiveRole,FaultManagementAPI.acknowledgeFault/shelveFault, import/export actions, notebook entry create/delete. No external sinkAuditLoggerSpec.js,UserAPISpec.js,FaultManagementAPISpec.js,notebook-entriesSpec.jsRoot cause for the error-message findings (F-02/04/06/07/08/11): the raw-error-to-operator pattern was repeated at six sites with no central rule. R3 centralizes provider failures in
PersistenceErrorso any caller displayingerror.messagefrom the object API now shows generic text; the UI-level sites were fixed individually. Audit hooks were placed at the API layer where one exists (UserAPI,FaultManagementAPI) so every caller is covered.Documented / needs-input
Evidence an ISSM/assessor must supply (details in the doc): CouchDB TLS configuration and version policy (F-15); URL indicator target scheme (F-14); CouchDB authentication and
_securityrole model plus the productionUserProvider/IdP/MFA (F-16, F-17); proxy/IdP session timeout, logoff and cookie flags (F-19); data-sensitivity determination for browserlocalStorageand CouchDB host encryption (F-18); reverse-proxy security headers (CSP, HSTS,X-Content-Type-Options,frame-ancestors); anopenmct.auditprovider forwarding to the site log store (F-20).Test baseline comparison
npm run lintnpm testmaster(a4aae41af)7c8deeb07)The six baseline specs are environment-sensitive, are not touched by this PR, and did not reproduce on the final run (CI
unit-testalso passes); +92 specs, no regressions. Notebook e2e link tests run locally vianpm run test:e2e:ci -- tests/functional/plugins/notebook/notebook.e2e.spec.js: 17 passed / 22 skipped (upstreamfixme), no e2e test edited. cspell entries added:STIG,DISA,ISSM,remediations,rethrew,notexample,Deployers,stig.Original prompt
All Submissions:
openmct.auditis a new API; persistence providers now reject withopenmct.objects.errors.Persistenceinstead of rawfetch/browser errors; Import-from-JSON now rejects trees that previously imported partially.Author Checklist
type:label? Note: this is not necessarily the same as the original issue.npm run lint && npm test)Reviewer Checklist
Link to Devin session: https://app.devin.ai/sessions/9a388bf2196f49ee9af1542b613e2510
Open in Devin Desktop: https://app.devin.ai/desktop/session/9a388bf2196f49ee9af1542b613e2510?variant=devin
Requested by: @erikrozi