mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-18 05:02:15 +01:00
fix(exiftool): remove System: prefixes
This commit is contained in:
@@ -268,15 +268,18 @@ func (engine *ExifTool) WriteMetadata(ctx context.Context, logger *slog.Logger,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter user-supplied metadata to prevent ExifTool pseudo-tags from
|
// Filter user-supplied metadata to prevent ExifTool pseudo-tags from
|
||||||
// triggering dangerous side effects like file renames, moves, or link
|
// triggering dangerous side effects like file renames, moves, link
|
||||||
// creation. Comparison is case-insensitive because ExifTool processes
|
// creation, or permission changes. Comparison is case-insensitive
|
||||||
// tag names case-insensitively.
|
// because ExifTool processes tag names case-insensitively, and group
|
||||||
|
// prefixes are stripped because ExifTool treats "System:FileName" the
|
||||||
|
// same as "FileName".
|
||||||
// See https://exiftool.org/TagNames/Extra.html.
|
// See https://exiftool.org/TagNames/Extra.html.
|
||||||
dangerousTags := []string{
|
dangerousTags := []string{
|
||||||
"FileName", // Writing this triggers a file rename in ExifTool
|
"FileName", // Writing this triggers a file rename in ExifTool
|
||||||
"Directory", // Writing this triggers a file move in ExifTool
|
"Directory", // Writing this triggers a file move in ExifTool
|
||||||
"HardLink", // Writing this creates a hard link in ExifTool
|
"HardLink", // Writing this creates a hard link in ExifTool
|
||||||
"SymLink", // Writing this creates a symbolic link in ExifTool
|
"SymLink", // Writing this creates a symbolic link in ExifTool
|
||||||
|
"FilePermissions", // Writing this changes the file's permissions
|
||||||
}
|
}
|
||||||
// Reject metadata keys containing characters that could inject ExifTool
|
// Reject metadata keys containing characters that could inject ExifTool
|
||||||
// stdin arguments. ExifTool uses a line-based stdin protocol; a newline
|
// stdin arguments. ExifTool uses a line-based stdin protocol; a newline
|
||||||
@@ -293,8 +296,16 @@ func (engine *ExifTool) WriteMetadata(ctx context.Context, logger *slog.Logger,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for key := range metadata {
|
for key := range metadata {
|
||||||
|
// Strip ExifTool group prefixes (e.g., "System:FileName" →
|
||||||
|
// "FileName") before comparing. ExifTool allows leading group
|
||||||
|
// names separated by colons, and treats the prefixed and bare
|
||||||
|
// forms identically.
|
||||||
|
bare := key
|
||||||
|
if i := strings.LastIndex(key, ":"); i >= 0 {
|
||||||
|
bare = key[i+1:]
|
||||||
|
}
|
||||||
for _, tag := range dangerousTags {
|
for _, tag := range dangerousTags {
|
||||||
if strings.EqualFold(key, tag) {
|
if strings.EqualFold(bare, tag) {
|
||||||
delete(metadata, key)
|
delete(metadata, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,6 +123,26 @@ Feature: /forms/pdfengines/metadata/{write|read}
|
|||||||
At least one PDF engine cannot process the requested metadata
|
At least one PDF engine cannot process the requested metadata
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
Scenario: POST /forms/pdfengines/metadata/write (Reject Group-Prefixed Dangerous Tag)
|
||||||
|
# Regression: ExifTool treats "System:FileName" identically to "FileName".
|
||||||
|
# The dangerous-tag blocklist must strip group prefixes before comparing,
|
||||||
|
# otherwise the attacker renames/moves files with a single HTTP request.
|
||||||
|
Given I have a default Gotenberg container
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/write" endpoint with the following form data and header(s):
|
||||||
|
| files | testdata/page_1.pdf | file |
|
||||||
|
| metadata | {"System:FileName":"stolen.pdf","System:Directory":"/tmp","Author":"legit"} | field |
|
||||||
|
| Gotenberg-Output-Filename | foo | header |
|
||||||
|
Then the response status code should be 200
|
||||||
|
Then the response header "Content-Type" should be "application/pdf"
|
||||||
|
Then there should be 1 PDF(s) in the response
|
||||||
|
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
|
||||||
|
| files | teststore/foo.pdf | file |
|
||||||
|
Then the response status code should be 200
|
||||||
|
Then the response body should contain string:
|
||||||
|
"""
|
||||||
|
"Author":"legit"
|
||||||
|
"""
|
||||||
|
|
||||||
Scenario: POST /forms/pdfengines/metadata/read (Bad Request)
|
Scenario: POST /forms/pdfengines/metadata/read (Bad Request)
|
||||||
Given I have a default Gotenberg container
|
Given I have a default Gotenberg container
|
||||||
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
|
When I make a "POST" request to Gotenberg at the "/forms/pdfengines/metadata/read" endpoint with the following form data and header(s):
|
||||||
|
|||||||
Reference in New Issue
Block a user