Skip to content

Commit d9fbc67

Browse files
MicroFish91Copilot
andauthored
Move CoR artifact security guidance into its own docs (#1875)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 78fcab3 commit d9fbc67

4 files changed

Lines changed: 106 additions & 78 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
description: 'Securely parse and render untrusted Copilot on Rails workspace artifacts.'
3+
applyTo: "src/webviews/copilotOnRails/**, src/commands/copilotOnRails/**, src/chat/tools/copilotOnRails/**, src/utils/copilotOnRails/**, src/tree/project/**, resources/agents/**, test/copilotOnRails/**"
4+
---
5+
6+
# Secure Copilot on Rails artifact handling
7+
8+
Treat `.azure/*`, `.azure/.preview-temp/*`, `.copilot-azure/sessions/*`, and `package.json` files inside
9+
the Copilot on Rails user's project workspace as untrusted and potentially incomplete. Agents, users, and
10+
other workspace tools can edit them, and readers can observe a partial write.
11+
12+
When code reads or renders these artifacts:
13+
14+
- Use one-argument `JSON.parse(text)`, assign the result to `unknown`, and narrow the root and every consumed
15+
field with runtime checks.
16+
- Preserve valid fields and array entries in an incomplete artifact. Do not coerce unsupported values into
17+
strings.
18+
- Validate artifact-supplied path parts before joining paths. Validate URLs, commands, process arguments,
19+
file operations, HTML, and SVG for their specific destination.
20+
- Render agent-written Markdown as parsed React nodes rather than with `dangerouslySetInnerHTML`. Explicitly
21+
allowlist link protocols and supported HTML tags. Configure Mermaid with `securityLevel: "strict"` before
22+
rendering.
23+
- Add targeted tests for malformed roots, wrong field types, partial objects, traversal strings, unsafe
24+
links or tags, and other invalid inputs that reach the changed destination.
25+
26+
Follow the full [Copilot on Rails artifact security contract](../../docs/copilot-create-project-security.md).
27+
Update that document when the trust boundary or required handling changes.

.github/instructions/copilot-on-rails-docs.instructions.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ Update the matching section of `docs/copilot-create-project.md` when you:
2727
| Change what diagnostics capture, or the Report Issue / Inspect Diagnostics behavior | Support & triage runbook, including the "What the diagnostics contain (privacy)" section |
2828
| Change the launch / resume / empty-folder / autopilot flow | Launching, Resuming a session, and Autopilot mode |
2929

30-
**Security rule:** when CoR code starts reading a new agent or workspace artifact, consumes a new field,
31-
constructs a path, command, or URL from artifact data, or renders artifact text as HTML or SVG, follow and
32-
update [Safe parsing and rendering](../../docs/copilot-create-project.md#safe-parsing-and-rendering). Also
33-
update **Files & state** when the artifact inventory changes.
30+
**Security documentation:** when the artifact trust boundary or required handling changes, update
31+
[Copilot on Rails artifact security](../../docs/copilot-create-project-security.md). Also update
32+
**Files & state** when the artifact inventory changes. Secure implementation requirements live in the
33+
separate Copilot on Rails artifact security instruction.
3434

3535
## New or changed UI — flag screenshots to re-capture
3636

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copilot on Rails artifact security
2+
3+
This document is the security contract for contributors and reviewers working on code that reads or renders
4+
Copilot on Rails artifacts. See [Files & state](copilot-create-project.md#files--state) for the artifact
5+
inventory.
6+
7+
## Trust boundary
8+
9+
**SDL requirement.** Treat `.azure/*`, `.azure/.preview-temp/*`,
10+
`.copilot-azure/sessions/*`, and `package.json` files inside the Copilot on Rails user's project workspace
11+
as untrusted input. Agents may write these files, and users and other workspace tools can edit them. A
12+
reader can also observe a partial write. Validate data before it influences a path, URL, command, process,
13+
file operation, HTML node, or SVG node.
14+
15+
**Design assumptions.** Artifacts belong to the current workspace and may be incomplete while an agent is
16+
working. Readers may preserve fields that are already valid, but they must not infer that the rest of the
17+
document is trustworthy.
18+
19+
**Residual risk.** Runtime shape checks do not make a string safe for every later use. Validate again for the
20+
specific sink. A future deserializer, renderer, or URL handler can introduce a new execution path even when
21+
the current JSON parsing step is data-only.
22+
23+
## JSON parsing and partial artifacts
24+
25+
Safe deserialization and safe downstream use are separate checks.
26+
27+
Use plain, one-argument `JSON.parse(text)`. This operation is data-only. JSON content cannot supply or invoke
28+
a reviver; application code would have to pass the optional second argument. Do not add a reviver without a
29+
separate security review.
30+
31+
Assign the parse result to `unknown`. Narrow the root and every consumed field with runtime checks before use.
32+
A TypeScript cast only changes the compiler's view and does not validate runtime data.
33+
34+
Malformed JSON follows the caller's existing error or retry path. For valid JSON with an incomplete object,
35+
preserve valid fields and ignore or default invalid fields according to the artifact contract. Filtering an
36+
invalid array entry must not discard its valid siblings. Never silently coerce an object to a string, which
37+
can turn unsupported input into text such as `[object Object]`.
38+
39+
## Paths and package metadata
40+
41+
Validate every artifact-supplied path part before passing it to `Uri.joinPath`, `path.join`, or another file
42+
API. Preview page slugs use kebab case and must match `[a-z0-9]+(?:-[a-z0-9]+)*`. A value such as
43+
`../outside` must fail validation before the code constructs `<slug>.html`; joining first would let the
44+
artifact escape the preview directory.
45+
46+
When reading a `package.json` from the user's project workspace, require an object root. Require
47+
`dependencies`, `devDependencies`, and `scripts` to be object records when present. Preserve entries whose
48+
values are strings and drop entries with other value types. When key presence changes behavior, use an
49+
own-property check such as `Object.hasOwn(record, key)` rather than reading through the prototype chain.
50+
51+
## Markdown, HTML, and SVG
52+
53+
Prefer a small parsed node model and React nodes for agent-written Markdown. Do not use
54+
`dangerouslySetInnerHTML` for plan text. Explicitly allowlist link protocols before creating anchors. The
55+
local debug plan currently allows `http`, `https`, and `mailto`. Restore only the HTML tags required by the
56+
plan contract, currently attribute-free `<details>`, `<summary>`, and `<br>` tags. Leave unknown or
57+
attribute-bearing HTML as text.
58+
59+
Mermaid output is still generated SVG inserted into the document. Initialize Mermaid with
60+
`securityLevel: "strict"` before rendering and keep that setting in place before inserting its SVG.
61+
62+
## Audit checklist
63+
64+
1. Find every JSON parse, file read, and deserializer used by the changed flow.
65+
2. Confirm each `JSON.parse` call has one argument and no reviver. Review deserializer dependencies for code
66+
execution or unsafe object construction.
67+
3. Parse into `unknown`, validate the root, and narrow every consumed field at runtime.
68+
4. Check malformed JSON follows the existing error or retry path. Check incomplete objects preserve valid
69+
fields without coercing invalid values.
70+
5. Trace artifact values into path construction, shell or process calls, file operations, and URLs. Apply
71+
sink-specific validation and confinement.
72+
6. Trace artifact text into HTML and SVG sinks. Prefer React nodes, allowlist protocols and tags, and keep
73+
Mermaid in strict security mode.
74+
7. Add targeted tests for malformed roots, wrong field types, partial objects, traversal strings, unsafe
75+
links or tags, and other inputs that reach the changed sink.

docs/copilot-create-project.md

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ the work as it happens.
3434
- [The agents](#the-agents)
3535
- [The MCP tools](#the-mcp-tools)
3636
- [Files & state](#files--state)
37-
- [Safe parsing and rendering](#safe-parsing-and-rendering)
3837
- [Part 5 — Support & triage runbook](#part-5--support--triage-runbook)
3938
- [Report an issue](#report-an-issue)
4039
- [Inspect diagnostics](#inspect-diagnostics)
@@ -495,79 +494,6 @@ app (`az containerapp exec`, `az webapp ssh`), then a one‑shot job in the same
495494
firewall rule is a last resort, and it is never widened beyond a single address — see
496495
[`cor-references/migration-access.md`](../resources/agents/azure-deploy/cor-references/migration-access.md).
497496

498-
## Safe parsing and rendering
499-
500-
This section is the security contract for code that reads or renders the artifacts above.
501-
502-
### Trust boundary
503-
504-
**SDL requirement.** Treat `.azure/*`, `.azure/.preview-temp/*`,
505-
`.copilot-azure/sessions/*`, and workspace `package.json` files as untrusted input. Agents may write these
506-
files, and users and other workspace tools can edit them. A reader can also observe a partial write. Validate
507-
data before it influences a path, URL, command, process, file operation, HTML node, or SVG node.
508-
509-
**Design assumptions.** Artifacts belong to the current workspace and may be incomplete while an agent is
510-
working. Readers may preserve fields that are already valid, but they must not infer that the rest of the
511-
document is trustworthy.
512-
513-
**Residual risk.** Runtime shape checks do not make a string safe for every later use. Validate again for the
514-
specific sink. A future deserializer, renderer, or URL handler can introduce a new execution path even when
515-
the current JSON parsing step is data-only.
516-
517-
### JSON parsing and partial artifacts
518-
519-
Safe deserialization and safe downstream use are separate checks.
520-
521-
Use plain, one-argument `JSON.parse(text)`. This operation is data-only. JSON content cannot supply or invoke
522-
a reviver; application code would have to pass the optional second argument. Do not add a reviver without a
523-
separate security review.
524-
525-
Assign the parse result to `unknown`. Narrow the root and every consumed field with runtime checks before use.
526-
A TypeScript cast only changes the compiler's view and does not validate runtime data.
527-
528-
Malformed JSON follows the caller's existing error or retry path. For valid JSON with an incomplete object,
529-
preserve valid fields and ignore or default invalid fields according to the artifact contract. Filtering an
530-
invalid array entry must not discard its valid siblings. Never silently coerce an object to a string, which
531-
can turn unsupported input into text such as `[object Object]`.
532-
533-
### Paths and package metadata
534-
535-
Validate every artifact-supplied path part before passing it to `Uri.joinPath`, `path.join`, or another file
536-
API. Preview page slugs use kebab case and must match `[a-z0-9]+(?:-[a-z0-9]+)*`. A value such as
537-
`../outside` must fail validation before the code constructs `<slug>.html`; joining first would let the
538-
artifact escape the preview directory.
539-
540-
When reading a workspace `package.json`, require an object root. Require `dependencies`, `devDependencies`,
541-
and `scripts` to be object records when present. Preserve entries whose values are strings and drop entries
542-
with other value types. When key presence changes behavior, use an own-property check such as
543-
`Object.hasOwn(record, key)` rather than reading through the prototype chain.
544-
545-
### Markdown, HTML, and SVG
546-
547-
Prefer a small parsed node model and React nodes for agent-written Markdown. Do not use
548-
`dangerouslySetInnerHTML` for plan text. Allowlist link protocols before creating anchors. The local debug
549-
plan currently allows `http`, `https`, and `mailto`. Restore only the tags required by the plan contract,
550-
currently attribute-free `<details>`, `<summary>`, and `<br>` tags. Leave unknown or attribute-bearing HTML
551-
as text.
552-
553-
Mermaid output is still generated SVG inserted into the document. Initialize Mermaid with
554-
`securityLevel: "strict"` before rendering and keep that setting in place before inserting its SVG.
555-
556-
### Audit Checklist
557-
558-
1. Find every JSON parse, file read, and deserializer used by the changed flow.
559-
2. Confirm each `JSON.parse` call has one argument and no reviver. Review deserializer dependencies for code
560-
execution or unsafe object construction.
561-
3. Parse into `unknown`, validate the root, and narrow every consumed field at runtime.
562-
4. Check malformed JSON follows the existing error or retry path. Check incomplete objects preserve valid
563-
fields without coercing invalid values.
564-
5. Trace artifact values into path construction, shell or process calls, file operations, and URLs. Apply
565-
sink-specific validation and confinement.
566-
6. Trace artifact text into HTML and SVG sinks. Prefer React nodes, allowlist protocols and tags, and keep
567-
Mermaid in strict security mode.
568-
7. Add targeted tests for malformed roots, wrong field types, partial objects, traversal strings, unsafe
569-
links or tags, and other inputs that reach the changed sink.
570-
571497
---
572498

573499
# Part 5 — Support & triage runbook

0 commit comments

Comments
 (0)