Skip to content

Latest commit

 

History

History
173 lines (142 loc) · 10.6 KB

File metadata and controls

173 lines (142 loc) · 10.6 KB

Mitigation Strategies Analysis for ianstormtaylor/slate

Description:

  1. Define Allowed Nodes (Slate API): Use Slate's concept of node types. Create a JavaScript object (the schema) that explicitly lists all allowed type values for Slate nodes (e.g., paragraph, heading, image, link). This leverages Slate's built-in node representation.
  2. Define Allowed Properties (Slate API): For each allowed node type, define the allowed properties (data fields) that the node can have. This uses Slate's data model. For example, a link node might have href and target as properties stored in its data map.
  3. Define Allowed Attributes (Slate API - within data): Within the data property of each node, define allowed attributes and their data types. This is how Slate handles attributes. The href of a link is not a top-level property; it's within the data map.
  4. Enforce on Input (Slate API - normalizeNode): Crucially, use Slate's normalizeNode function. This is a core Slate API function designed for schema enforcement. Implement this function as part of your editor configuration. It receives a node and the editor instance.
    • Pasting: Intercept paste events and use editor.insertFragment after normalizing the pasted fragment using your schema.
    • Typing: Normalize within the onChange handler, using the editor instance to apply changes that enforce the schema.
    • Programmatic Insertion: If you use editor.insertNode or similar, normalize the node before insertion.
    • Initial Value: Normalize the initialValue passed to the Slate editor.
  5. Reject Invalid Data (Slate API - within normalizeNode): Within normalizeNode, use the editor instance to perform operations that enforce the schema:
    • editor.removeNodeByKey: Remove invalid nodes.
    • editor.setNodeByKey: Modify nodes to make them valid (e.g., change their type or update their data).
    • editor.wrapNodeByKey / editor.unwrapNodeByKey: Restructure the node tree to enforce parent-child relationships.
  6. Regular Review: Periodically review the schema object to ensure it remains appropriate.
  • Threats Mitigated:

    • Cross-Site Scripting (XSS) (High Severity): Prevents injection of malicious nodes that could execute JavaScript.
    • HTML Injection (High Severity): Prevents injection of arbitrary HTML structures.
    • Data Corruption (Medium Severity): Prevents invalid Slate Value objects.
    • Unexpected Behavior (Low Severity): Ensures consistent editor behavior.
  • Impact:

    • XSS: 90-95% risk reduction.
    • HTML Injection: 90-95% risk reduction.
    • Data Corruption: 70-80% risk reduction.
    • Unexpected Behavior: 60-70% risk reduction.
  • Currently Implemented:

    • Example: "Schema defined in src/schema/slateSchema.ts. normalizeNode implemented in src/components/MyEditor.tsx and used in onChange and a custom onPaste plugin."
  • Missing Implementation:

    • Example: "Schema not enforced on initial editor load. blockquote allows arbitrary attributes within its data."

Description:

  1. Identify Sensitive Attributes (Slate's data): Within your schema definition, identify attributes stored in the data property of your custom nodes that require sanitization (e.g., image src, link href).
  2. Create Sanitization Functions: Write JavaScript functions to sanitize these attributes.
  3. Integrate with normalizeNode (Slate API): Crucially, call these sanitization functions within your normalizeNode implementation. This is where you have access to the node and the editor instance.
    // In normalizeNode:
    if (node.type === 'image') {
      const sanitizedSrc = sanitizeImageSrc(node.data.get('src')); // Access via data.get()
      if (sanitizedSrc !== node.data.get('src')) {
        editor.setNodeByKey(node.key, { // Use editor to update
          data: node.data.set('src', sanitizedSrc) // Use data.set()
        });
      }
    }
  4. Access and Modify Data (Slate API): Use node.data.get('attributeName') to access attribute values and node.data.set('attributeName', newValue) to modify them, combined with editor.setNodeByKey. This is the correct way to interact with node data within Slate.
  • Threats Mitigated:

    • Cross-Site Scripting (XSS) (High Severity): Sanitizes attributes that could contain malicious scripts.
    • Phishing Attacks (High Severity): Sanitizes href attributes.
    • Malware Distribution (High Severity): Sanitizes src attributes.
    • Data Exfiltration (Medium Severity): Prevents attribute-based data exfiltration.
  • Impact:

    • XSS: Additional 5-10% risk reduction (on top of schema).
    • Phishing: 80-90% risk reduction.
    • Malware: 80-90% risk reduction.
    • Data Exfiltration: 60-70% risk reduction.
  • Currently Implemented:

    • Example: "Sanitization functions in src/utils/sanitization.ts. Called within normalizeNode in src/components/MyEditor.tsx."
  • Missing Implementation:

    • Example: "No sanitization on custom data-* attributes. link sanitization only checks protocol."

Description:

  1. Choose a Serializer (Slate API or Custom): Select or create a serializer to convert the Slate Value to your output format (HTML, JSON, etc.). You might use:
    • slate-html-serializer: A common choice for HTML.
    • slate-hyperscript: For creating a Value from JSX-like syntax.
    • A custom serializer: If you need a specific output format.
  2. HTML Output (Critical - with Slate Serializer):
    • Configure the Serializer: If using slate-html-serializer, configure its rules to match your schema. This is a key step. The serializer should only output HTML that corresponds to your allowed node types and attributes.
    • Example (slate-html-serializer):
      import { Html } from 'slate-html-serializer';
      
      const rules = [
        {
          deserialize(el, next) {
            if (el.tagName.toLowerCase() === 'p') {
              return {
                object: 'block',
                type: 'paragraph',
                nodes: next(el.childNodes),
              };
            }
            // ... rules for other node types ...
          },
          serialize(obj, children) {
            if (obj.object === 'block' && obj.type === 'paragraph') {
              return <p>{children}</p>;
            }
            // ... rules for other node types ...
          },
        },
      ];
      
      const html = new Html({ rules });
      const slateValue = html.deserialize(someHtmlString); // Deserialize
      const serializedHtml = html.serialize(slateValue); // Serialize
    • Post-Serialization Sanitization: Even with a configured serializer, use a library like DOMPurify after serialization as an additional layer of defense.
  3. JSON Output (Slate's Value is already JSON): The Slate Value itself is a JSON-serializable object. You can use JSON.stringify(value) directly.
  4. Custom Output Formats (Custom Serializer): If using a custom serializer, you must implement appropriate escaping and encoding within that serializer.
  • Threats Mitigated:

    • Cross-Site Scripting (XSS) (High Severity): Prevents XSS that might bypass input sanitization.
    • HTML Injection (High Severity): Prevents HTML injection.
    • JSON Injection (High Severity): Not applicable if using JSON.stringify directly on the Value.
    • Other Injection Vulnerabilities (Variable Severity): Depends on the custom serializer.
  • Impact:

    • XSS: Crucial second layer of defense (80-90% reduction).
    • HTML Injection: 80-90% reduction.
    • JSON Injection: Eliminated with JSON.stringify.
  • Currently Implemented:

    • Example: "Using slate-hyperscript and DOMPurify. Sanitization in src/utils/serializeContent.ts."
  • Missing Implementation:

    • Example: "Markdown output not sanitized. DOMPurify config needs review."

Description:

  1. Understand Relationships: Define the allowed relationships between Slate node types (parent-child, siblings).
  2. Create Validation Functions: Write functions that use the Slate API to traverse the Value and check relationships.
  3. Check for Inconsistencies (Slate API): Use Slate's API functions to check for issues:
    • value.document.getParent(node.key): Check parent nodes.
    • value.document.nodes: Iterate over all nodes.
    • node.type: Check node types.
    • node.data.get('attribute'): Check attribute values.
    • value.document.getDepth(node.key): Check node depth.
  4. Integrate with onChange (Slate API): Call these validation functions within your onChange handler. This gives you access to the current value.
    const onChange = ({ value }) => {
      validateDataModel(value); // Pass the Slate Value
      // ...
    };
  5. Handle Invalid Data (Slate API): If validation fails, use the editor instance (available in onChange or normalizeNode) to correct the data model or revert the change.
  • Threats Mitigated:

    • Data Corruption (Medium Severity): Prevents invalid Slate Value states.
    • Unexpected Behavior (Low Severity): Ensures consistent editor behavior.
    • Subtle Exploits (Medium Severity): Prevents exploits that bypass schema validation.
  • Impact:

    • Data Corruption: 50-60% risk reduction.
    • Unexpected Behavior: 40-50% risk reduction.
    • Subtle Exploits: 30-40% risk reduction.
  • Currently Implemented:

    • Example: "Basic validation in src/utils/validation.ts, called in onChange in src/components/MyEditor.tsx."
  • Missing Implementation:

    • Example: "No validation for table cells. Validation needs to cover all node types."