Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
0d4b2579
authored
May 19, 2026
by
Seefs
Committed by
GitHub
May 19, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: expose param override audits for sensitive message fields (#4974)
parent
146dd77b
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
114 additions
and
13 deletions
+114
-13
relay/common/override.go
+22
-10
relay/common/override_test.go
+90
-0
web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx
+2
-3
No files found.
relay/common/override.go
View file @
0d4b2579
...
...
@@ -26,13 +26,20 @@ const (
var
errSourceHeaderNotFound
=
errors
.
New
(
"source header does not exist"
)
var
paramOverrideKeyAuditPaths
=
map
[
string
]
struct
{}{
"model"
:
{},
"original_model"
:
{},
"upstream_model"
:
{},
"service_tier"
:
{},
"inference_geo"
:
{},
"speed"
:
{},
var
paramOverrideSensitivePathPrefixes
=
[]
string
{
"model"
,
"original_model"
,
"upstream_model"
,
"service_tier"
,
"inference_geo"
,
"speed"
,
"messages"
,
"input"
,
"instructions"
,
"system"
,
"contents"
,
"systemInstruction"
,
"system_instruction"
,
}
type
paramOverrideAuditRecorder
struct
{
...
...
@@ -206,6 +213,7 @@ func shouldEnableParamOverrideAudit(paramOverride map[string]interface{}) bool {
if
operations
,
ok
:=
tryParseOperations
(
paramOverride
);
ok
{
for
_
,
operation
:=
range
operations
{
if
shouldAuditParamPath
(
strings
.
TrimSpace
(
operation
.
Path
))
||
shouldAuditParamPath
(
strings
.
TrimSpace
(
operation
.
From
))
||
shouldAuditParamPath
(
strings
.
TrimSpace
(
operation
.
To
))
{
return
true
}
...
...
@@ -255,15 +263,19 @@ func shouldAuditParamPath(path string) bool {
if
common
.
DebugEnabled
{
return
true
}
_
,
ok
:=
paramOverrideKeyAuditPaths
[
path
]
return
ok
for
_
,
prefix
:=
range
paramOverrideSensitivePathPrefixes
{
if
path
==
prefix
||
strings
.
HasPrefix
(
path
,
prefix
+
"."
)
{
return
true
}
}
return
false
}
func
shouldAuditOperation
(
mode
,
path
,
from
,
to
string
)
bool
{
if
common
.
DebugEnabled
{
return
true
}
for
_
,
candidate
:=
range
[]
string
{
path
,
to
}
{
for
_
,
candidate
:=
range
[]
string
{
path
,
from
,
to
}
{
if
shouldAuditParamPath
(
candidate
)
{
return
true
}
...
...
relay/common/override_test.go
View file @
0d4b2579
...
...
@@ -12,6 +12,7 @@ import (
"github.com/QuantumNous/new-api/dto"
"github.com/QuantumNous/new-api/setting/model_setting"
"github.com/samber/lo"
"github.com/stretchr/testify/require"
)
func
TestApplyParamOverrideTrimPrefix
(
t
*
testing
.
T
)
{
...
...
@@ -2184,6 +2185,95 @@ func TestApplyParamOverrideWithRelayInfoRecordsOnlyKeyOperationsWhenDebugDisable
}
}
func
TestApplyParamOverrideWithRelayInfoRecordsConversationBodyOperationsWhenDebugDisabled
(
t
*
testing
.
T
)
{
originalDebugEnabled
:=
common2
.
DebugEnabled
common2
.
DebugEnabled
=
false
t
.
Cleanup
(
func
()
{
common2
.
DebugEnabled
=
originalDebugEnabled
})
info
:=
&
RelayInfo
{
ChannelMeta
:
&
ChannelMeta
{
ParamOverride
:
map
[
string
]
interface
{}{
"operations"
:
[]
interface
{}{
map
[
string
]
interface
{}{
"mode"
:
"replace"
,
"path"
:
"messages.0.content"
,
"from"
:
"hello"
,
"to"
:
"hi"
,
},
map
[
string
]
interface
{}{
"mode"
:
"set"
,
"path"
:
"input.0.content.0.text"
,
"value"
:
"rewritten response input"
,
},
map
[
string
]
interface
{}{
"mode"
:
"set"
,
"path"
:
"instructions"
,
"value"
:
"new instruction"
,
},
map
[
string
]
interface
{}{
"mode"
:
"append"
,
"path"
:
"contents.0.parts"
,
"value"
:
map
[
string
]
interface
{}{
"text"
:
"new gemini part"
},
},
map
[
string
]
interface
{}{
"mode"
:
"copy"
,
"from"
:
"system"
,
"to"
:
"metadata.system_copy"
,
},
map
[
string
]
interface
{}{
"mode"
:
"set"
,
"path"
:
"temperature"
,
"value"
:
0.1
,
},
},
},
},
}
out
,
err
:=
ApplyParamOverrideWithRelayInfo
([]
byte
(
`{
"messages":[{"role":"user","content":"hello world"}],
"input":[{"role":"user","content":[{"type":"input_text","text":"original response input"}]}],
"instructions":"old instruction",
"system":"old system",
"contents":[{"role":"user","parts":[{"text":"hello gemini"}]}],
"temperature":0.7
}`
),
info
)
require
.
NoError
(
t
,
err
)
assertJSONEqual
(
t
,
`{
"messages":[{"role":"user","content":"hi world"}],
"input":[{"role":"user","content":[{"type":"input_text","text":"rewritten response input"}]}],
"instructions":"new instruction",
"system":"old system",
"contents":[{"role":"user","parts":[{"text":"hello gemini"},{"text":"new gemini part"}]}],
"temperature":0.1,
"metadata":{"system_copy":"old system"}
}`
,
string
(
out
))
require
.
Equal
(
t
,
[]
string
{
"replace messages.0.content from hello to hi"
,
"set input.0.content.0.text = rewritten response input"
,
"set instructions = new instruction"
,
"append contents.0.parts with {
\"
text
\"
:
\"
new gemini part
\"
}"
,
"copy system -> metadata.system_copy"
,
},
info
.
ParamOverrideAudit
)
}
func
TestShouldAuditParamPathUsesFieldBoundaryPrefixMatching
(
t
*
testing
.
T
)
{
originalDebugEnabled
:=
common2
.
DebugEnabled
common2
.
DebugEnabled
=
false
t
.
Cleanup
(
func
()
{
common2
.
DebugEnabled
=
originalDebugEnabled
})
require
.
True
(
t
,
shouldAuditParamPath
(
"messages"
))
require
.
True
(
t
,
shouldAuditParamPath
(
"messages.0.content"
))
require
.
True
(
t
,
shouldAuditParamPath
(
"systemInstruction.parts.0.text"
))
require
.
False
(
t
,
shouldAuditParamPath
(
"model_name"
))
require
.
False
(
t
,
shouldAuditParamPath
(
"message"
))
}
func
assertJSONEqual
(
t
*
testing
.
T
,
want
,
got
string
)
{
t
.
Helper
()
...
...
web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx
View file @
0d4b2579
...
...
@@ -985,9 +985,8 @@ export function DetailsDialog(props: DetailsDialogProps) {
</
DetailSection
>
)
}
{
/* Param override (admin only) */
}
{
props
.
isAdmin
&&
other
?.
po
&&
{
/* Param override */
}
{
other
?.
po
&&
Array
.
isArray
(
other
.
po
)
&&
other
.
po
.
length
>
0
&&
(
<
DetailSection
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment