{"id":1724,"date":"2025-02-12T17:15:47","date_gmt":"2025-02-12T17:15:47","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/02\/12\/how-github-uses-codeql-to-secure-github\/"},"modified":"2025-02-12T17:15:47","modified_gmt":"2025-02-12T17:15:47","slug":"how-github-uses-codeql-to-secure-github","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2025\/02\/12\/how-github-uses-codeql-to-secure-github\/","title":{"rendered":"How GitHub uses CodeQL to secure GitHub"},"content":{"rendered":"<p>GitHub\u2019s Product Security Engineering team writes code and implements tools that help secure the code that powers GitHub. We use GitHub Advanced Security (GHAS) to discover, track, and remediate vulnerabilities and enforce secure coding standards at scale. One tool we rely heavily on to analyze our code at scale is <a href=\"https:\/\/codeql.github.com\/\">CodeQL<\/a>.<\/p>\n<p>CodeQL is GitHub\u2019s static analysis engine that powers automated security analyses. You can use it to query code in much the same way you would query a database. It provides a much more robust way to analyze code and uncover problems than an old-fashioned text search through a codebase.<\/p>\n<p>The following post will detail how we use CodeQL to keep GitHub secure and how you can apply these lessons to your own organization. You will learn why and how we use:<\/p>\n<p>Custom query packs (and how we create and manage them).<br \/>\nCustom queries.<br \/>\nVariant analysis to uncover potentially insecure programming practices.<\/p>\n<h2>Enabling CodeQL at scale<a href=\"https:\/\/github.blog\/engineering\/how-github-uses-codeql-to-secure-github\/#enabling-codeql-at-scale\" class=\"heading-link pl-2 text-italic text-bold\"><\/a><\/h2>\n<p>We employ CodeQL in a variety of ways at GitHub.<\/p>\n<p><strong><a href=\"https:\/\/docs.github.com\/en\/code-security\/code-scanning\/enabling-code-scanning\/configuring-default-setup-for-code-scanning\">Default setup<\/a><\/strong> with the <a href=\"https:\/\/docs.github.com\/en\/code-security\/code-scanning\/managing-your-code-scanning-configuration\/codeql-query-suites#built-in-codeql-query-suites\">default and security-extended query suites<\/a><br \/>\nDefault setup with the default and security-extended query suites meets the needs of the vast majority of our over 10,000 repositories. With these settings, pull requests automatically get a security review from CodeQL.<br \/>\n<strong><a href=\"https:\/\/docs.github.com\/en\/code-security\/code-scanning\/creating-an-advanced-setup-for-code-scanning\/configuring-advanced-setup-for-code-scanning\">Advanced setup<\/a> with a custom query pack<\/strong><br \/>\nA few repositories, like our large Ruby monolith, need extra special attention, so we use advanced setup with a <a href=\"https:\/\/docs.github.com\/en\/code-security\/codeql-cli\/getting-started-with-the-codeql-cli\/customizing-analysis-with-codeql-packs#about-codeql-packs\">query pack<\/a> containing custom queries to really tailor to our needs.<br \/>\n<strong><a href=\"https:\/\/docs.github.com\/en\/code-security\/codeql-for-vs-code\/getting-started-with-codeql-for-vs-code\/running-codeql-queries-at-scale-with-multi-repository-variant-analysis\">Multi-repository variant analysis<\/a> (MRVA)<\/strong><br \/>\nTo conduct variant analysis and quick auditing, we use MRVA. We also write custom CodeQL queries to detect code patterns that are either specific to GitHub\u2019s codebases or patterns we want a security engineer to manually review.<\/p>\n<p>The specific custom Actions workflow step we use on our monolith is pretty simple. It looks like this:<\/p>\n<p>&#8211; name: Initialize CodeQL<br \/>\n    uses: github\/codeql-action\/init@v3<br \/>\n    with:<br \/>\n      languages: ${{ matrix.language }}<br \/>\n      config-file: .\/.github\/codeql\/${{ matrix.language }}\/codeql-config.yml<\/p>\n<p>Our Ruby configuration is pretty standard, but advanced setup offers a variety of <a href=\"https:\/\/docs.github.com\/en\/code-security\/code-scanning\/creating-an-advanced-setup-for-code-scanning\/customizing-your-advanced-setup-for-code-scanning#using-a-custom-configuration-file\">configuration options using custom configuration files<\/a>. The interesting part is the packs option, which is how we enable our custom query pack as part of the CodeQL analysis. This pack contains a collection of CodeQL queries we have written for Ruby, specifically for the GitHub codebase.<\/p>\n<p>So, let\u2019s dive deeper into why we did that\u2014and how!<\/p>\n<h2>Publishing our CodeQL query pack<a href=\"https:\/\/github.blog\/engineering\/how-github-uses-codeql-to-secure-github\/#publishing-our-codeql-query-pack\" class=\"heading-link pl-2 text-italic text-bold\"><\/a><\/h2>\n<p>Initially, we published CodeQL query files directly to the GitHub monolith repository, but we moved away from this approach for several reasons:<\/p>\n<p>It required going through the production deployment process for each new or updated query.<br \/>\nQueries not included in a query pack were <a href=\"https:\/\/docs.github.com\/en\/code-security\/codeql-cli\/using-the-advanced-functionality-of-the-codeql-cli\/publishing-and-using-codeql-packs#about-codeql-pack-compatibility\">not pre-compiled<\/a>, which slowed down CodeQL analysis in CI.<br \/>\nOur <a href=\"https:\/\/docs.github.com\/en\/code-security\/codeql-cli\/using-the-advanced-functionality-of-the-codeql-cli\/testing-custom-queries\">test suite for CodeQL queries<\/a> ran as part of the monolith\u2019s CI jobs. When a new version of the CodeQL CLI was released, it sometimes caused the query tests to fail because of changes in the query output, even when there were no changes to the code in the pull request. This often led to confusion and frustration among engineers, as the failure wasn\u2019t related to their pull request changes.<\/p>\n<p>By switching to publishing a query pack to <a href=\"https:\/\/docs.github.com\/en\/packages\/working-with-a-github-packages-registry\/working-with-the-container-registry\">GitHub Container Registry (GCR)<\/a>, we\u2019ve simplified our process and eliminated many of these pain points, making it easier to ship and maintain our CodeQL queries. So while it\u2019s <em>possible<\/em> to deploy custom CodeQL query files directly to a repository, we recommend publishing CodeQL queries as a query pack to the GCR for easier deployment and faster iteration.<\/p>\n<h2>Creating our query pack<a href=\"https:\/\/github.blog\/engineering\/how-github-uses-codeql-to-secure-github\/#creating-our-query-pack\" class=\"heading-link pl-2 text-italic text-bold\"><\/a><\/h2>\n<p>When setting up our custom <a href=\"https:\/\/docs.github.com\/en\/code-security\/codeql-cli\/using-the-advanced-functionality-of-the-codeql-cli\/creating-and-working-with-codeql-packs#codeql-pack-structure\">query pack<\/a>, we faced several considerations, particularly around managing dependencies like the ruby-all package.<\/p>\n<p>To ensure our custom queries remain maintainable and concise, we extend classes from the <a href=\"https:\/\/docs.github.com\/en\/code-security\/code-scanning\/managing-your-code-scanning-configuration\/ruby-built-in-queries\">default query suite<\/a>, such as the ruby-all library. This allows us to leverage existing functionality rather than reinventing the wheel, keeping our queries concise and maintainable. However, changes to the CodeQL library API can introduce breaking changes, potentially deprecating our queries or causing errors. Since CodeQL runs as part of our CI, we wanted to minimize the chance of this happening, as this can lead to frustration and loss of trust from developers.<\/p>\n<p>We develop our queries against the latest version of the ruby-all package, ensuring we\u2019re always working with the most up-to-date functionality. To mitigate the risk of breaking changes affecting CI, we pin the ruby-all version when we\u2019re ready to release, <a href=\"https:\/\/docs.github.com\/en\/code-security\/codeql-cli\/using-the-advanced-functionality-of-the-codeql-cli\/creating-and-working-with-codeql-packs%5C%5C#adding-and-installing-dependencies-on-a-codeql-pack\">locking it in the codeql-pack.lock.yml file<\/a>. This guarantees that when our queries are deployed, they will run with the specific version of ruby-all we\u2019ve tested, avoiding potential issues from unintentional updates.<\/p>\n<p>Here\u2019s how we manage this setup:<\/p>\n<p>In our qlpack.yml, we set the dependency to use the latest version of ruby-all<br \/>\nDuring development, this configuration <a href=\"https:\/\/docs.github.com\/en\/code-security\/codeql-cli\/using-the-advanced-functionality-of-the-codeql-cli\/creating-and-working-with-codeql-packs#adding-and-installing-dependencies-on-a-codeql-pack%5C\">pulls in the latest version<\/a>) of ruby-all when running codeql pack init, ensuring we\u2019re always up to date.<br \/>\n\/\/ Our custom query pack&#8217;s qlpack.yml<\/p>\n<p>library: false<br \/>\nname: github\/internal-ruby-codeql<br \/>\nversion: 0.2.3<br \/>\nextractor: &#8216;ruby&#8217;<br \/>\ndependencies:<br \/>\n  codeql\/ruby-all: &#8220;*&#8221;<br \/>\ntests: &#8216;test&#8217;<br \/>\ndescription: &#8220;Ruby CodeQL queries used internally at GitHub&#8221;<\/p>\n<p>Before releasing, we lock the version in the <a href=\"https:\/\/docs.github.com\/en\/code-security\/codeql-cli\/using-the-advanced-functionality-of-the-codeql-cli\/creating-and-working-with-codeql-packs#codeql-pack-structure\">codeql-pack.lock.yml<\/a> file, specifying the exact version to ensure stability and prevent issues in CI.<br \/>\n\/\/ Our custom query pack&#8217;s codeql-pack.lock.yml<\/p>\n<p>lockVersion: 1.0.0<br \/>\ndependencies:<br \/>\n &#8230;<br \/>\n codeql\/ruby-all:<br \/>\n   version: 1.0.6<\/p>\n<p>This approach allows us to balance developing against the latest features of the ruby-all package while ensuring stability when we release.<\/p>\n<p>We also have a set of <a href=\"https:\/\/docs.github.com\/en\/code-security\/codeql-cli\/using-the-advanced-functionality-of-the-codeql-cli\/testing-custom-queries\">CodeQL unit tests<\/a> that exercise our queries against sample code snippets, which helps us quickly determine if any query will cause errors before we publish our pack. These tests are run as part of the CI process in our query pack repository, providing an early check for issues. We strongly recommend writing unit tests for your custom CodeQL queries to ensure stability and reliability.<\/p>\n<p>Altogether, the basic flow for releasing new CodeQL queries via our pack is as follows:<\/p>\n<p>Open a pull request with the new query.<br \/>\nWrite unit tests for the new query.<br \/>\nMerge the pull request.<br \/>\nIncrement the pack version in a new pull request.<br \/>\nRun codeql pack init to resolve dependencies.<br \/>\nCorrect unit tests as needed.<br \/>\nPublish the query pack to the GitHub Container Registry (GCR).<br \/>\nRepositories with the query pack in their config will start using the updated queries.<\/p>\n<p>We have found this flow balances our team\u2019s development experience while ensuring stability in our published query pack.<\/p>\n<h2>Configuring our repository to use our custom query pack<a href=\"https:\/\/github.blog\/engineering\/how-github-uses-codeql-to-secure-github\/#configuring-our-repository-to-use-our-custom-query-pack\" class=\"heading-link pl-2 text-italic text-bold\"><\/a><\/h2>\n<p>We won\u2019t provide a general recommendation on configuration here, given that it ultimately depends on how your organization deploys code. We opted against locking our pack to a particular version in our <a href=\"https:\/\/docs.github.com\/en\/code-security\/code-scanning\/creating-an-advanced-setup-for-code-scanning\/customizing-your-advanced-setup-for-code-scanning#using-codeql-model-packs\">CodeQL configuration file<\/a> (see above). Instead, we chose to manage our versioning by publishing the CodeQL package in GCR. This results in the GitHub monolith retrieving the latest published version of the query pack. To roll back changes, we simply have to republish the package. In one instance, we released a query that had a high number of false positives and we were able to publish a new version of the pack that removed that query in less than 15 minutes. This is faster than the time it would have taken us to merge a pull request on the monolith repository to roll back the version in the CodeQL configuration file.<\/p>\n<p>One of the problems we encountered with publishing the query pack in GCR was how to easily make the package available to multiple repositories within our enterprise. There are several approaches we explored.<\/p>\n<p><strong>Grant access permissions for individual repositories.<\/strong> On the package management page, you can grant permissions for individual repositories to access your package. This was not a good solution for us since we have too many repositories for it to be feasible to do manually, yet there is not currently a way to configure programmatically using an API.<br \/>\n<strong>Mint a personal access token for the CodeQL action runner.<\/strong> We could have minted a personal access token (PAT) that has access to read all packages for our organization and added that to the CodeQL action runner. However, this would have required managing a new token, and it seemed a bit more permissive than we wanted because it could read <em>all<\/em> of our private packages rather than ones we explicitly allow it to have access to.<br \/>\n<strong>Provide access permissions via a linked repository.<\/strong> We ended up implementing the third solution that we explored. We <a href=\"https:\/\/docs.github.com\/en\/packages\/learn-github-packages\/connecting-a-repository-to-a-package#connecting-a-repository-to-an-organization-scoped-package-on-github\">link a repository to the package<\/a> and allow the package to <a href=\"https:\/\/docs.github.com\/en\/packages\/learn-github-packages\/configuring-a-packages-access-control-and-visibility#about-inheritance-of-access-permissions\">inherit access permissions from the linked repository<\/a>.  <\/p>\n<h2>CodeQL query pack queries<a href=\"https:\/\/github.blog\/engineering\/how-github-uses-codeql-to-secure-github\/#codeql-query-pack-queries\" class=\"heading-link pl-2 text-italic text-bold\"><\/a><\/h2>\n<p>We write a variety of custom queries to be used in our custom query packs. These cover GitHub-specific patterns that aren\u2019t included in the default CodeQL query pack. This allows us to tailor the analysis to patterns and preferences that are specific to our company and codebase. Some of the types of things we alert on using our custom query pack include:<\/p>\n<p>High-risk APIs specific to GitHub\u2019s code that can be dangerous if they receive unsanitized user input.<br \/>\nUse of specific built-in Rails methods for which we have safer, custom methods or functions.<br \/>\nRequired authorization methods not being used in our REST API endpoint definitions and GraphQL object\/mutation definitions.<br \/>\nREST API endpoints and GraphQL mutations that require engineers to define access control methods to determine which actors can access them. (Specifically, the query detects the absence of this method definition to ensure that the actors\u2019 permissions are being checked for these endpoints.)<br \/>\nUse of signed tokens so we can nudge engineers to include Product Security as a reviewer when using them.<\/p>\n<p>Custom queries can be used more for educational purposes rather than being blockers to shipping code. For example, we want to alert engineers when they use the <a href=\"https:\/\/guides.rubyonrails.org\/active_record_encryption.html#encrypt-and-decrypt\">ActiveRecord::decrypt<\/a> method. This method should generally not be used in production code, as it will cause an encrypted column to become decrypted. We use the recommendation severity in the <a href=\"https:\/\/codeql.github.com\/docs\/writing-codeql-queries\/metadata-for-codeql-queries\/#metadata-properties\">query metadata<\/a> so these alerts are treated as more of an informational alert. That means this may trigger an alert in a pull request, but it won\u2019t cause the CodeQL CI job to fail. We use this lower severity level to allow engineers to assess the impact of new queries without immediate blocking. Additionally, this alert level isn\u2019t tracked through our <a href=\"https:\/\/github.blog\/engineering\/githubs-engineering-fundamentals-program-how-we-deliver-on-availability-security-and-accessibility\/\">Fundamentals program<\/a>, meaning it doesn\u2019t require immediate action, reflecting the query\u2019s maturity as we continue to refine its relevance and risk assessment.<\/p>\n<p>\/**<br \/>\n * @id rb\/github\/use-of-activerecord-decrypt<br \/>\n * @description Do not use the .decrypt method on AR models, this will decrypt all encrypted attributes and save<br \/>\n * them unencrypted, effectively undoing encryption and possibly making the attributes inaccessible.<br \/>\n * If you need to access the unencrypted value of any attribute, you can do so by calling my_model.attribute_name.<br \/>\n * @kind problem<br \/>\n * @severity recommendation<br \/>\n * @name Use of ActiveRecord decrypt method<br \/>\n * @tags security<br \/>\n *      github-internal<br \/>\n *\/<\/p>\n<p>import ruby<br \/>\nimport DataFlow<br \/>\nimport codeql.ruby.DataFlow<br \/>\nimport codeql.ruby.frameworks.ActiveRecord<\/p>\n<p>\/** Match against .decrypt method calls where the receiver may be an ActiveRecord object *\/<br \/>\nclass ActiveRecordDecryptMethodCall extends ActiveRecordInstanceMethodCall {<br \/>\n  ActiveRecordDecryptMethodCall() { this.getMethodName() = &#8220;decrypt&#8221; }<br \/>\n}<\/p>\n<p>from ActiveRecordDecryptMethodCall call<br \/>\nselect call,<br \/>\n  &#8220;Do not use the .decrypt method on AR models, this will decrypt all encrypted attributes and save them unencrypted.<\/p>\n<p>Another educational query is the one mentioned above in which we detect the absence of the `control_access` method in a class that defines a REST API endpoint. If a pull request introduces a new endpoint without `control_access`,  a comment will appear on the pull request saying that the `control_access` method wasn\u2019t found and it\u2019s a requirement for REST API endpoints. This will notify the reviewer of a potential issue and prompt the developer to fix it.<\/p>\n<p>\/**<br \/>\n * @id rb\/github\/api-control-access<br \/>\n * @name Rest API Without &#8216;control_access&#8217;<br \/>\n * @description All REST API endpoints must call the &#8216;control_access&#8217; method, to ensure that only specified actor types are able to access the given endpoint.<br \/>\n * @kind problem<br \/>\n * @tags security<br \/>\n * github-internal<br \/>\n * @precision high<br \/>\n * @problem.severity recommendation<br \/>\n *\/<\/p>\n<p>import codeql.ruby.AST<br \/>\nimport codeql.ruby.DataFlow<br \/>\nimport codeql.ruby.TaintTracking<br \/>\nimport codeql.ruby.ApiGraphs<\/p>\n<p>\/\/ Api::App REST API endpoints should generally call the control_access method<br \/>\nprivate DataFlow::ModuleNode appModule() {<br \/>\n  result = API::getTopLevelMember(&#8220;Api&#8221;).getMember(&#8220;App&#8221;).getADescendentModule() and<br \/>\n  not result = protectedApiModule() and<br \/>\n  not result = staffAppApiModule()<br \/>\n}<\/p>\n<p>\/\/ Api::Admin, Api::Staff, Api::Internal, and Api::ThirdParty REST API endpoints do not need to call the control_access method<br \/>\nprivate DataFlow::ModuleNode protectedApiModule() {<br \/>\n  result =<br \/>\n    API::getTopLevelMember([&#8220;Api&#8221;])<br \/>\n        .getMember([&#8220;Admin&#8221;, &#8220;Staff&#8221;, &#8220;Internal&#8221;, &#8220;ThirdParty&#8221;])<br \/>\n        .getADescendentModule()<br \/>\n}<\/p>\n<p>\/\/ Api::Staff::App REST API endpoints do not need to call the control_access method<br \/>\nprivate DataFlow::ModuleNode staffAppApiModule() {<br \/>\n  result =<br \/>\n    API::getTopLevelMember([&#8220;Api&#8221;]).getMember(&#8220;Staff&#8221;).getMember(&#8220;App&#8221;).getADescendentModule()<br \/>\n}<\/p>\n<p>private class ApiRouteWithoutControlAccess extends DataFlow::CallNode {<br \/>\n  ApiRouteWithoutControlAccess() {<br \/>\n    this = appModule().getAModuleLevelCall([&#8220;get&#8221;, &#8220;post&#8221;, &#8220;delete&#8221;, &#8220;patch&#8221;, &#8220;put&#8221;]) and<br \/>\n    not performsAccessControl(this.getBlock())<br \/>\n  }<br \/>\n}<\/p>\n<p>predicate performsAccessControl(DataFlow::BlockNode blocknode) {<br \/>\n  accessControlCalled(blocknode.asExpr().getExpr())<br \/>\n}<\/p>\n<p>predicate accessControlCalled(Block block) {<br \/>\n  \/\/ the method `control_access` is called somewhere inside `block`<br \/>\n  block.getAStmt().getAChild*().(MethodCall).getMethodName() = &#8220;control_access&#8221;<br \/>\n}<\/p>\n<p>from ApiRouteWithoutControlAccess api<br \/>\nselect api.getLocation(),<br \/>\n  &#8220;The control_access method was not detected in this REST API endpoint. All REST API endpoints must call this method to ensure that the endpoint is only accessible to the specified actor types.&#8221;<\/p>\n<h2>Variant analysis<a href=\"https:\/\/github.blog\/engineering\/how-github-uses-codeql-to-secure-github\/#variant-analysis\" class=\"heading-link pl-2 text-italic text-bold\"><\/a><\/h2>\n<p><a href=\"https:\/\/codeql.github.com\/docs\/codeql-overview\/about-codeql\/#about-variant-analysis\">Variant analysis (VA)<\/a> refers to the process of searching for variants of security vulnerabilities. This is particularly useful when we\u2019re responding to a <a href=\"https:\/\/bounty.github.com\/\">bug bounty submission<\/a> or a security incident. We use a combination of tools to do this, including GitHub\u2019s code search functionality, custom scripts, and CodeQL.  We will often start by using code search to find patterns similar to the one that caused a particular vulnerability across numerous repositories. This is sometimes not good enough, as code search is not semantically aware, meaning that it cannot determine whether a given variable is an Active Record object or whether it is being used in an `if` expression. To answer those types of questions we turn to CodeQL.<\/p>\n<p>When we write CodeQL queries for variant analysis we are much less concerned about false positives, since the goal is to provide results for security engineers to analyze. The quality of the code is also not quite as important, as these queries will only be used for the duration of the VA effort. Some of the types of things we use CodeQL for during VAs are:<\/p>\n<p>Where are we using SHA1 hashes?<br \/>\nOne of our internal API endpoints was vulnerable to SQLi according to a recent bug bounty report. Where are we passing user input to that API endpoint?<br \/>\nThere is a problem with how some HTTP request libraries in Ruby handle the proxy setting. Can we look at places we are instantiating our HTTP request libraries with a proxy setting?<\/p>\n<p>One recent example involved a subtle vulnerability in Rails. We wanted to detect when the following condition was present in our code:<\/p>\n<p>A parameter was used to look up an Active Record object.<br \/>\nThat parameter is later reused after the Active Record object is looked up.<\/p>\n<p>The concern with this condition is that it could lead to an <a href=\"https:\/\/portswigger.net\/web-security\/access-control\/idor\">insecure direct object<\/a> reference (IDOR) vulnerability because Active Record finder methods can accept an array. If the code looks up an Active Record object in one call to determine if a given entity has access to a resource, but later uses a different element from that array to find an object reference, that can lead to an IDOR vulnerability. It would be difficult to write a query to detect <em>all<\/em> vulnerable instances of this pattern, but we were able to write a query that found potential vulnerabilities that gave us a list of code paths to manually analyze. We ran the query against a large number of our Ruby codebases using CodeQL\u2019s MRVA.<\/p>\n<p>The query, which is a bit hacky and not quite production grade, is below:<\/p>\n<p>\/**<br \/>\n * @name wip array query<br \/>\n * @description an array is passed to an AR finder object<br \/>\n *\/<\/p>\n<p>import ruby<br \/>\nimport codeql.ruby.AST<br \/>\nimport codeql.ruby.ApiGraphs<br \/>\nimport codeql.ruby.frameworks.Rails<br \/>\nimport codeql.ruby.frameworks.ActiveRecord<br \/>\nimport codeql.ruby.frameworks.ActionController<br \/>\nimport codeql.ruby.DataFlow<br \/>\nimport codeql.ruby.Frameworks<br \/>\nimport codeql.ruby.TaintTracking<\/p>\n<p>\/\/ Gets the &#8220;final&#8221; receiver in a chain of method calls.<br \/>\n\/\/ For example, in `Foo.bar`, this would give the `Foo` access, and in<br \/>\n\/\/ `foo.bar.baz(&#8220;arg&#8221;)` it would give the `foo` variable access<br \/>\nprivate Expr getUltimateReceiver(MethodCall call) {<br \/>\n  exists(Expr recv |<br \/>\n    recv = call.getReceiver() and<br \/>\n    (<br \/>\n      result = getUltimateReceiver(recv)<br \/>\n      or<br \/>\n      not recv instanceof MethodCall and result = recv<br \/>\n    )<br \/>\n  )<br \/>\n}<\/p>\n<p>\/\/ Names of class methods on ActiveRecord models that may return one or more<br \/>\n\/\/ instances of that model. This also includes the `initialize` method.<br \/>\n\/\/ See https:\/\/api.rubyonrails.org\/classes\/ActiveRecord\/FinderMethods.html<br \/>\nprivate string staticFinderMethodName() {<br \/>\n  exists(string baseName |<br \/>\n    baseName = [&#8220;find_by&#8221;, &#8220;find_or_create_by&#8221;, &#8220;find_or_initialize_by&#8221;, &#8220;where&#8221;] and<br \/>\n    result = baseName + [&#8220;&#8221;, &#8220;!&#8221;]<br \/>\n  )<br \/>\n  \/\/ or<br \/>\n  \/\/ result = [&#8220;new&#8221;, &#8220;create&#8221;]<br \/>\n}<\/p>\n<p>private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation, DataFlow::CallNode<br \/>\n{<br \/>\n  private ActiveRecordModelClass cls;<\/p>\n<p>  ActiveRecordModelFinderCall() {<br \/>\n    exists(MethodCall call, Expr recv |<br \/>\n      call = this.asExpr().getExpr() and<br \/>\n      recv = getUltimateReceiver(call) and<br \/>\n      (<br \/>\n        \/\/ The receiver refers to an `ActiveRecordModelClass` by name<br \/>\n        recv.(ConstantReadAccess).getAQualifiedName() = cls.getAQualifiedName()<br \/>\n        or<br \/>\n        \/\/ The receiver is self, and the call is within a singleton method of<br \/>\n        \/\/ the `ActiveRecordModelClass`<br \/>\n        recv instanceof SelfVariableAccess and<br \/>\n        exists(SingletonMethod callScope |<br \/>\n          callScope = call.getCfgScope() and<br \/>\n          callScope = cls.getAMethod()<br \/>\n        )<br \/>\n      ) and<br \/>\n      (<br \/>\n        call.getMethodName() = staticFinderMethodName()<br \/>\n        or<br \/>\n        \/\/ dynamically generated finder methods<br \/>\n        call.getMethodName().indexOf(&#8220;find_by_&#8221;) = 0<br \/>\n      )<br \/>\n    )<br \/>\n  }<\/p>\n<p>  final override ActiveRecordModelClass getClass() { result = cls }<br \/>\n}<\/p>\n<p>class FinderCallArgument extends DataFlow::Node {<br \/>\n  private ActiveRecordModelFinderCall finderCallNode;<\/p>\n<p>  FinderCallArgument() { this = finderCallNode.getArgument(_) }<br \/>\n}<\/p>\n<p>class ParamsHashReference extends DataFlow::CallNode {<br \/>\n  private Rails::ParamsCall params;<\/p>\n<p>  \/\/ TODO: only direct element references against `params` calls are considered<br \/>\n  ParamsHashReference() { this.getReceiver().asExpr().getExpr() = params }<\/p>\n<p>  string getArgString() {<br \/>\n    result = this.getArgument(0).asExpr().getConstantValue().getStringlikeValue()<br \/>\n  }<br \/>\n}<\/p>\n<p>class ArrayPassedToActiveRecordFinder extends TaintTracking::Configuration {<br \/>\n  ArrayPassedToActiveRecordFinder() { this = &#8220;ArrayPassedToActiveRecordFinder&#8221; }<\/p>\n<p>  override predicate isSource(DataFlow::Node source) { source instanceof ParamsHashReference }<\/p>\n<p>  override predicate isSink(DataFlow::Node sink) {<br \/>\n    sink instanceof FinderCallArgument<br \/>\n  }<\/p>\n<p>  string getParamsArg(DataFlow::CallNode paramsCall) {<br \/>\n    result = paramsCall.getArgument(0).asExpr().getConstantValue().getStringlikeValue()<br \/>\n  }<\/p>\n<p>  \/\/ this doesn&#8217;t check for anything fancy like whether it&#8217;s reuse in a if\/else<br \/>\n  \/\/ only intended for quick manual audit filtering of interesting candidates<br \/>\n  \/\/ so remains fairly broad to not induce false negatives<br \/>\n  predicate paramsUsedAfterLookups(DataFlow::Node source) {<br \/>\n    exists(DataFlow::CallNode y | y instanceof ParamsHashReference<br \/>\n    and source.getEnclosingMethod() = y.getEnclosingMethod()<br \/>\n    and source != y<br \/>\n    and getParamsArg(source) = getParamsArg(y)<br \/>\n    \/\/ we only care if it&#8217;s used again AFTER an object lookup<br \/>\n    and y.getLocation().getStartLine() &gt; source.getLocation().getStartLine())<br \/>\n  }<br \/>\n}<\/p>\n<p>from ArrayPassedToActiveRecordFinder config, DataFlow::Node source, DataFlow::Node sink<br \/>\nwhere config.hasFlow(source, sink) and config.paramsUsedAfterLookups(source)<br \/>\nselect source, sink.getLocation()<\/p>\n<h2>Conclusion<a href=\"https:\/\/github.blog\/engineering\/how-github-uses-codeql-to-secure-github\/#conclusion\" class=\"heading-link pl-2 text-italic text-bold\"><\/a><\/h2>\n<p>CodeQL can be very useful for product security engineering teams to detect and prevent vulnerabilities at scale. We use a combination of queries that run in CI using our query pack and one-off queries run through MRVA to find potential vulnerabilities and communicate them to engineers. CodeQL isn\u2019t only useful for finding security vulnerabilities, though; it is also useful for detecting the presence or absence of security controls that are defined in code. This saves our security team time by surfacing certain security problems automatically, and saves our engineers time by detecting them earlier in the development process.<\/p>\n<h2>Writing custom CodeQL queries<a href=\"https:\/\/github.blog\/engineering\/how-github-uses-codeql-to-secure-github\/#writing-custom-codeql-queries\" class=\"heading-link pl-2 text-italic text-bold\"><\/a><\/h2>\n<h3>Tips for getting started<a href=\"https:\/\/github.blog\/engineering\/how-github-uses-codeql-to-secure-github\/#tips-for-getting-started\" class=\"heading-link pl-2 text-italic text-bold\"><\/a><\/h3>\n<p>We have a large number of articles and resources for writing custom CodeQL queries. If you haven\u2019t written custom CodeQL queries before, here are some resources to help get you started:<\/p>\n<p><a href=\"https:\/\/github.blog\/developer-skills\/github\/codeql-zero-to-hero-part-1-the-fundamentals-of-static-analysis-for-vulnerability-research\/\">CodeQL zero to hero part 1: The fundamentals of static analysis for vulnerability research &#8211; The GitHub Blog<\/a><br \/>\n<a href=\"https:\/\/codeql.github.com\/docs\/writing-codeql-queries\/\">Writing CodeQL queries<\/a><br \/>\n<a href=\"https:\/\/docs.github.com\/en\/code-security\/codeql-for-vs-code\">Use CodeQL inside Visual Studio Code &#8211; GitHub Docs<\/a><br \/>\n<a href=\"https:\/\/github.com\/githubuniverseworkshops\/codeql\">CodeQL workshops for GitHub Universe<\/a> and <a href=\"https:\/\/github.com\/githubsatelliteworkshops\/codeql\">GitHub Satellite 2020 workshops on finding security vulnerabilities with CodeQL for Java\/JavaScript.<\/a><br \/>\n<a href=\"https:\/\/github.com\/readme\/guides\/custom-codeql-queries\">A beginner\u2019s guide to running and managing custom CodeQL queries<\/a><\/p>\n<div class=\"post-content-cta\">\n<p>Improve the security of your applications today by <a href=\"https:\/\/docs.github.com\/en\/code-security\/code-scanning\/enabling-code-scanning\/configuring-default-setup-for-code-scanning#configuring-default-setup-for-a-repository\">enabling CodeQL for free on your public repositories<\/a>, or try <a href=\"https:\/\/github.com\/enterprise\/advanced-security\">GitHub Advanced Security<\/a> for your organization.<\/p>\n<\/div>\n<p><em>Michael Recachinas, GitHub Staff Security Engineer, also contributed to this blog post.<\/em><\/p>\n<p>The post <a href=\"https:\/\/github.blog\/engineering\/how-github-uses-codeql-to-secure-github\/\">How GitHub uses CodeQL to secure GitHub<\/a> appeared first on <a href=\"https:\/\/github.blog\/\">The GitHub Blog<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>GitHub\u2019s Product Security Engineering team writes code and implements tools that help secure the code that powers GitHub. We use [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[8],"tags":[],"class_list":["post-1724","post","type-post","status-publish","format-standard","hentry","category-github-engineering"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/1724","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=1724"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/1724\/revisions"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=1724"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=1724"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=1724"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}