in the GmxProxy contract
The function setPerpVault(...) uses tx.origin == owner() instead of the more standard msg.sender == owner(). This reliance on tx.origin poses a security risk and deviates from the contract’s typical ownership pattern.
Because setPerpVault uses tx.origin == owner() instead of the typical msg.sender == owner(), it’s vulnerable to indirect calls through malicious contracts that can hijack or redirect perpVault assignment. Standardizing on the usual “onlyOwner” pattern is safer and consistent with the rest of the contract.
RootCause & Where It Happens
Inside the setPerpVault function:
Notice that to restrict calls to the owner, the code checks:
while elsewhere in the contract, or in typical OpenZeppelin patterns, you use something like:
tx.origin Is ProblematicSusceptible to Proxy/Phishing Attacks
A malicious contract can trick an EOA user (who is the owner) into calling it. Because a user’s transaction going through another contract still has the same tx.origin (the user’s address), your setPerpVault call might be invoked under unexpected circumstances.
For instance, the malicious contract can call your function with the user’s tx.origin while msg.sender is the attacker contract. The check tx.origin == owner() passes, even though the direct caller is not owner.
Breaks the Usual “OnlyOwner” Pattern
Everywhere else, the code either uses onlyOwner or checks msg.sender == owner(), ensuring direct calls by the owner. Here, the logic is inconsistent. If later you rely on the same assumption that “the function’s msg.sender must be owner,” you might incorrectly trust calls from another contract.
Deviates from the rest of the contract
The rest of GmxProxy (and typical upgradeable OpenZeppelin code) uses onlyOwner or checks msg.sender == owner(). The mismatch leads to confusion or an unexpected security gap specifically in setPerpVault().
Potential Unauthorized Setting of perpVault: A malicious contract could engineer a call from the real owner’s EOA (with tx.origin == owner()) but route it through malicious code, letting that malicious contract control which _perpVault is set.
Once perpVault is set to a malicious address, the GmxProxy contract will forward funds, create orders, or do other logic tied to this malicious vault address—severely compromising the system.
Use msg.sender == owner() (like standard “onlyOwner” modifiers) instead of tx.origin. That is the canonical, secure way to restrict calls to the owner.
If you truly need the EOA check (very rare), adopt a well-documented flow that reverts if the call is from a contract, but this is generally discouraged in DeFi for flexibility and composability.
Even then, there are known techniques to circumvent EOA checks in advanced contexts.
Lightchaser: Medium-5
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.