fix: cap Base64 media transfers at 10 MB, upload limit at most 32 MB

This commit is contained in:
2026-09-26 05:04:38 +02:00
parent 7f58301a71
commit 28bb033a8b
12 changed files with 122 additions and 25 deletions
@@ -13,8 +13,9 @@ use WP_Error;
* Delivers a media file (original or a named image size) as an MCP embedded resource
* (spec §4.3). Direct tool: like ImageContent (lit-media-preview), an embedded resource
* is only turned into a content block by mcp-adapter for a tool called directly, never
* via mcp-adapter-execute-ability (ruling Q6). Files above the upload limit (Limits) are
* refused; the caller falls back to the URL.
* via mcp-adapter-execute-ability (ruling Q6). The whole file is read into memory and sent
* as Base64, so files above Limits::inlineBytes() (upload limit, at most 10 MB) are refused;
* the caller falls back to the file URL.
*/
final class MediaDownloadAbility implements Ability
{
@@ -35,7 +36,8 @@ final class MediaDownloadAbility implements Ability
public function description(): string
{
return 'Liefert eine Datei der Mediathek (Original oder Bildgröße, siehe sizes in lit/media-get) als '
. 'eingebettete Ressource. Dateien über dem Upload-Limit werden nicht übertragen; dann die URL nutzen.';
. 'eingebettete Ressource. Dateien über dem Upload-Limit (höchstens 10 MB) werden nicht übertragen; '
. 'dann die Datei-URL nutzen.';
}
public function inputSchema(): array
@@ -103,14 +105,14 @@ final class MediaDownloadAbility implements Ability
}
$bytesOnDisk = (int) filesize($path);
if ($bytesOnDisk > $this->limits->uploadBytes()) {
if ($bytesOnDisk > $this->limits->inlineBytes()) {
return Errors::unsupported(
sprintf(
'Die Datei ist zu groß für die Übertragung (%.1f MB, Limit %d MB).',
$bytesOnDisk / 1048576,
$this->limits->uploadMegabytes()
$this->limits->inlineMegabytes()
),
'Kleinere Bildgröße (size) wählen oder die URL aus lit/media-get verwenden.'
'Die Datei-URL (url aus lit/media-get) verwenden oder eine kleinere Bildgröße (size) wählen.'
);
}
+20 -5
View File
@@ -16,7 +16,8 @@ use WP_Error;
* - URL: only http(s), checked with wp_http_validate_url() before any request and fetched
* with wp_safe_remote_get() (rejects internal addresses, also after redirects), streamed
* into a temp file and cut off one byte above the upload limit.
* - Base64: decoded strictly; the size is checked before anything is decoded or written.
* - Base64: decoded strictly; the size is checked against Limits::inlineBytes() (upload limit,
* at most 10 MB – the whole file sits in memory) before anything is decoded or written.
* - Type: whitelist (filter lit_mcp_upload_mimes) intersected with what WordPress allows the
* current user (SVG etc. only if WordPress itself allows it), checked against the real
* file content with wp_check_filetype_and_ext() – disguised files fail.
@@ -83,8 +84,8 @@ class MediaImporter
public function fromBase64(string $data, string $filename, array $meta): int|WP_Error
{
$estimated = intdiv(strlen($data) * 3, 4);
if ($estimated > $this->limits->uploadBytes() + 2) {
return $this->tooLarge($estimated);
if ($estimated > $this->limits->inlineBytes() + 2) {
return $this->tooLargeInline($estimated);
}
$bytes = base64_decode($data, true);
@@ -95,8 +96,8 @@ class MediaImporter
);
}
if (strlen($bytes) > $this->limits->uploadBytes()) {
return $this->tooLarge(strlen($bytes));
if (strlen($bytes) > $this->limits->inlineBytes()) {
return $this->tooLargeInline(strlen($bytes));
}
AdminIncludes::load();
@@ -337,6 +338,20 @@ class MediaImporter
);
}
private function tooLargeInline(int $bytes): WP_Error
{
if ($this->limits->inlineMegabytes() === $this->limits->uploadMegabytes()) {
return $this->tooLarge($bytes);
}
return Errors::invalidInput(
sprintf('Datei zu groß (%.1f MB, Limit %d MB).', $bytes / 1048576, $this->limits->inlineMegabytes()),
['data' => 'über dem Limit für Base64-Uploads'],
'Größere Dateien über eine öffentliche URL mit lit/media-upload-from-url (direkt: '
. 'lit-media-upload-from-url) importieren.'
);
}
private function tooLarge(int $bytes, string $field = 'data'): WP_Error
{
return Errors::invalidInput(
@@ -10,7 +10,8 @@ use WP_Error;
/**
* Uploads a Base64-encoded file into the media library (spec §6.3), up to the configured
* upload limit. Checks and cleanup: MediaImporter; permission and result: MediaUploads.
* upload limit (at most Limits::INLINE_MAX_MB, the request carries the whole file).
* Checks and cleanup: MediaImporter; permission and result: MediaUploads.
*/
final class MediaUploadAbility implements Ability
{
@@ -36,8 +37,8 @@ final class MediaUploadAbility implements Ability
return sprintf(
'Lädt eine Datei (Bild, PDF, MP4, MP3) als Base64 in die Mediathek, höchstens %d MB; optional mit '
. 'Titel, Alt-Text und Zuordnung zu einem Eintrag (post_id). Nicht idempotent: jeder Aufruf legt '
. 'ein neues Medium an.',
$this->limits->uploadMegabytes()
. 'ein neues Medium an. Größere Dateien per URL mit lit/media-upload-from-url importieren.',
$this->limits->inlineMegabytes()
);
}