InfinityPool contract authorization bypass attack
An attacker could create their own credential and set the `Agent` ID to `0`, which would bypass the `subjectIsAgentCaller` modifier. The attacker could use this attack to `borrow` funds from the pool, draining any available liquidity. For example, only an `Agent` should be able to `borrow` funds from the pool and call the `borrow` function:\\n```\\nfunction borrow(VerifiableCredential memory vc) external isOpen subjectIsAgentCaller(vc) {\\n // 1e18 => 1 FIL, can't borrow less than 1 FIL\\n if (vc.value < WAD) revert InvalidParams();\\n // can't borrow more than the pool has\\n if (totalBorrowableAssets() < vc.value) revert InsufficientLiquidity();\\n Account memory account = \\_getAccount(vc.subject);\\n // fresh account, set start epoch and epochsPaid to beginning of current window\\n if (account.principal == 0) {\\n uint256 currentEpoch = block.number;\\n account.startEpoch = currentEpoch;\\n account.epochsPaid = currentEpoch;\\n GetRoute.agentPolice(router).addPoolToList(vc.subject, id);\\n }\\n\\n account.principal += vc.value;\\n account.save(router, vc.subject, id);\\n\\n totalBorrowed += vc.value;\\n\\n emit Borrow(vc.subject, vc.value);\\n\\n // interact - here `msg.sender` must be the Agent bc of the `subjectIsAgentCaller` modifier\\n asset.transfer(msg.sender, vc.value);\\n}\\n```\\n\\nThe following modifier checks that the caller is an Agent:\\n```\\nmodifier subjectIsAgentCaller(VerifiableCredential memory vc) {\\n if (\\n GetRoute.agentFactory(router).agents(msg.sender) != vc.subject\\n ) revert Unauthorized();\\n \\_;\\n}\\n```\\n\\nBut if the caller is not an `Agent`, the `GetRoute.agentFactory(router).agents(msg.sender)` will return `0`. And if the `vc.subject` is also zero, the check will be successful with any `msg.sender`. The attacker can also pass an arbitrary `vc.value` as the parameter and steal all the funds from the pool.
Ensure only an `Agent` can call `borrow` and pass the `subjectIsAgentCaller` modifier.
```\\nfunction borrow(VerifiableCredential memory vc) external isOpen subjectIsAgentCaller(vc) {\\n // 1e18 => 1 FIL, can't borrow less than 1 FIL\\n if (vc.value < WAD) revert InvalidParams();\\n // can't borrow more than the pool has\\n if (totalBorrowableAssets() < vc.value) revert InsufficientLiquidity();\\n Account memory account = \\_getAccount(vc.subject);\\n // fresh account, set start epoch and epochsPaid to beginning of current window\\n if (account.principal == 0) {\\n uint256 currentEpoch = block.number;\\n account.startEpoch = currentEpoch;\\n account.epochsPaid = currentEpoch;\\n GetRoute.agentPolice(router).addPoolToList(vc.subject, id);\\n }\\n\\n account.principal += vc.value;\\n account.save(router, vc.subject, id);\\n\\n totalBorrowed += vc.value;\\n\\n emit Borrow(vc.subject, vc.value);\\n\\n // interact - here `msg.sender` must be the Agent bc of the `subjectIsAgentCaller` modifier\\n asset.transfer(msg.sender, vc.value);\\n}\\n```\\n