---
title: "Security"
manual: "RTE CKEditor Image"
version: "main"
permalink: "https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:integration-security@main"
source: "Integration/Security.rst"
rendered: "2026-10-01T01:27:51+00:00"
---

# Security {#integration-security}

<!-- TODO: no Markdown rendering for "versionadded" -->

Comprehensive security measures including protocol blocking, file validation,
and XSS prevention.

Security features and best practices for the RTE CKEditor Image extension.

**Table of contents**

-   [Security architecture](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:security-architecture@main)
-   [Protocol blocking](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:protocol-blocking@main)
-   [File visibility validation](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:file-visibility-validation@main)
-   [XSS prevention](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:xss-prevention@main)
-   [Immutable DTOs](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:immutable-dtos@main)
-   [External link security (rel="noreferrer")](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:external-link-security-rel-noreferrer@main)
-   [SVG security](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:svg-security@main)
-   [Best practices](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:best-practices@main)
-   [Security reporting](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:security-reporting@main)
-   [Related documentation](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:related-documentation@main)

## Security architecture {#security-architecture}

The extension implements security at multiple layers:

```plantuml
skinparam componentStyle rectangle

package "1. Input Validation" {
    component "ImageResolverService" as Resolver
    note right of Resolver
        Protocol blocking
        File visibility check
        FAL validation
    end note
}

package "2. XSS Prevention" {
    component "ImageRenderingDto" as DTO
    note right of DTO
        htmlspecialchars encoding
        Readonly properties
        Immutable after creation
    end note
}

package "3. Output Rendering" {
    component "Fluid Templates" as Templates
    note right of Templates
        Pre-validated DTOs
        Auto-escaping enabled
    end note
}

Resolver --> DTO : validated data
DTO --> Templates : immutable data
```

Security layers architecture

## Protocol blocking {#protocol-blocking}

The `ImageResolverService` blocks dangerous URL protocols:

-   `javascript:` \- Prevents script execution via URLs.
-   `file:` \- Prevents local file system access.
-   `data:text/html` \- Prevents HTML injection via data URIs.
-   `vbscript:` \- Prevents VBScript execution (legacy IE).

**Safe protocols allowed:**

-   `http://` and `https://` \- Standard web URLs.
-   `/` \- Relative paths.
-   `t3://` \- TYPO3 link handler URLs.

## File visibility validation {#file-visibility-validation}

Before rendering, the extension validates:

1.  **File exists**: FAL file reference must be valid.
1.  **File accessible**: File must not be hidden or restricted.
1.  **Storage accessible**: File storage must be publicly accessible.

If validation fails, the original unprocessed content is returned.

## XSS prevention {#xss-prevention}

All user-controlled content is sanitized:

### Caption text {#caption-text}

**Caption sanitization**

```php
// Caption is sanitized with htmlspecialchars()
$caption = htmlspecialchars($rawCaption, ENT_QUOTES | ENT_HTML5, 'UTF-8');
```

### Alt and title attributes {#alt-and-title-attributes}

Alt and title text are sanitized before inclusion in HTML output.

### CSS classes {#css-classes}

CSS class names are validated and encoded to prevent attribute injection.

## Immutable DTOs {#immutable-dtos}

The `ImageRenderingDto` and `LinkDto` are declared as `readonly`:

**Readonly DTO declaration**

```php
final readonly class ImageRenderingDto
{
    // Properties cannot be modified after construction
}
```

This ensures:

-   **Data integrity**: Validated data cannot be corrupted.
-   **Audit trail**: Security validation happens once, at creation.
-   **Thread safety**: No race conditions on property access.

## External link security (`rel="noreferrer"`) {#integration-security-rel}

Automatic `rel="noreferrer"` on figure-wrapped linked images, mirroring
TYPO3 typolink semantics. Closes
[#799](https://github.com/netresearch/t3x-rte_ckeditor_image/issues/799)
(see [CHANGELOG.md](https://github.com/netresearch/t3x-rte_ckeditor_image/blob/main/CHANGELOG.md)
for the version this shipped in).

Linked images that are wrapped in `<figure>` (e.g. when a caption is set)
are rendered through the Fluid `Link.html` partial, which constructs
the `<a>` tag directly rather than going through TYPO3's `LinkFactory`.
That means `LinkFactory::addSecurityRelValues()` — the core helper that
appends `rel="noreferrer"` to external `target="_blank"` links to prevent
referrer leakage — never ran on this code path. The extension now mirrors
the typolink semantics in PHP via the `SecurityRelComputer` service.

### When the rule fires {#when-the-rule-fires}

`rel="noreferrer"` is appended automatically when **both** conditions hold:

1.  The link target opens a new browsing context — i.e. `target` is set
    and not one of `_self`, `_parent`, `_top` (case-insensitive,
    whitespace-tolerant per the HTML living standard).
1.  The URL is **external** — defined as either:

    -   An absolute `http://` or `https://` URL.
    -   A protocol-relative URL (e.g. `//example.com/image.jpg`,
        RFC 3986 §4.2 network-path reference) that inherits the page
        scheme but resolves to a different host.

Relative paths (`/fileadmin/...`), fragment links (`#section`),
`mailto:` / `tel:` schemes, and `t3://` URIs (already resolved before
this point) are treated as internal and don't trigger the addition.

### Token preservation {#token-preservation}

Pre-existing rel tokens from the source `<a>` tag — `nofollow`,
`sponsored`, `noopener`, custom values — are preserved through
`SecurityRelComputer::parseTokens()`, which lowercases, deduplicates,
and collapses whitespace. `noreferrer` is added at most once; if the
source already declares it, no duplicate is appended.

### Example {#example}

**Editor-set link with target="\_blank" and an external URL**

```html
<a href="https://example.com" target="_blank">
  <img src="/fileadmin/_processed_/image.jpg" alt="..." />
</a>
```

After rendering through the figure-wrapped path:

**Output — `rel="noreferrer"` injected automatically**

```html
<figure>
  <a href="https://example.com" target="_blank" rel="noreferrer">
    <img src="/fileadmin/_processed_/image.jpg" alt="..." />
  </a>
  <figcaption>...</figcaption>
</figure>
```

Internal links (e.g. `/about` or `t3://page?uid=42`) and links without
a `target` continue to render without `rel`, matching typolink behavior.

## SVG security {#svg-security}

> [!WARNING]
> SVG files can contain embedded JavaScript and are potential XSS vectors.
> The extension does not sanitize SVG content.

**Recommendations:**

1.  **Sanitize before upload**: Use server-side SVG sanitization libraries.
1.  **Restrict uploads**: Consider limiting SVG uploads to trusted users.
1.  **Content Security Policy**: Implement CSP headers to mitigate XSS risks.

> [!NOTE]
> The `allowSvgImages` option was removed in v13.1.5 due to security
> concerns. SVG files are now handled via the standard image workflow
> with automatic noScale mode.

## Best practices {#best-practices}

### File upload restrictions {#file-upload-restrictions}

Configure allowed file extensions in TYPO3:

**config/system/settings.php**

```php
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] = 'gif,jpg,jpeg,png,webp';
```

Restrict in RTE configuration:

**EXT:my_extension/Configuration/RTE/Custom.yaml**

```yaml
editor:
  externalPlugins:
    typo3image:
      allowedExtensions: "jpg,jpeg,png,gif,webp"
```

### Backend user permissions {#backend-user-permissions}

-   Configure appropriate file mounts for backend users.
-   Restrict upload folder access to necessary directories.
-   Use TYPO3 backend user groups for granular control.

### Content Security Policy {#content-security-policy}

Implement CSP headers for additional protection:

**.htaccess CSP configuration**

```apache
Header set Content-Security-Policy "default-src 'self'; img-src 'self' data: https:;"
```

### External image fetching {#external-image-fetching}

The `fetchExternalImages` option downloads external images to FAL:

**config/system/settings.php**

```php
$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['rte_ckeditor_image'] = [
    'fetchExternalImages' => true,  // Recommended: download to local storage
];
```

This prevents:

-   Hotlinking to external resources.
-   Privacy leaks via external image loading.
-   Broken images when external sources change.

### Regular updates {#regular-updates}

Keep the extension and TYPO3 core updated to receive security patches:

**Update extension via Composer**

```bash
composer update netresearch/rte-ckeditor-image
```

## Security reporting {#security-reporting}

Report security vulnerabilities to:

-   **TYPO3 Security Team**: [security@typo3.org](mailto:security@typo3.org)
-   **Extension maintainer**: Via GitHub issues (for non-critical issues)

## Related documentation {#related-documentation}

-   [ImageResolverService](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:api-imageresolverservice@main) \- Security validation implementation.
-   [Data Transfer Objects](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:api-dtos@main) \- Immutable data transfer objects.
-   [Advanced Configuration](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:integration-configuration-advanced@main) \- Extension configuration.
