Rules Reference

  • Authz before authn

    • Id
    • authz-before-authn
    • Impact Domain
    • Security
    • Scope
    • http_server_request

    Determines when authorization logic is applied to a user identity that has not been properly verified. Because the the user’s identity has not been verified yet, the outcome of the authorization check cannot be trusted. A malicious user might be able to get themselves authorized as a different user than they really are - or they may not be logged in at all.

    Rule logic

    Iterates over all descendants of the HTTP server request. If an event labeled security.authentication is encountered, the rule is satisfied. If an event labeled security.authorization is encountered, and the event returns a truthy value, the descendants of the authentication event are searched for an event labeled security.authentication. If such an event is found, the rule is satisfied. Otherwise a finding is emitted.

    Notes

    A security.authorization event which returns a falsey value (false, null, etc) will not trigger a finding.

    The security.authentication event must return a truthy value (true, any object) in order to satisfy the rule.

    Resolution

    Ensure that the user’s identity is established before performing authorization.

    Options

    None

    Examples

    - rule: authzBeforeAuthn
    

  • Circular dependency

    • Id
    • circular-dependency
    • Impact Domain
    • Maintainability
    • Scope
    • Labels

    Finds cycles in the package dependency graph. Cyclic dependencies make code hard to maintain, because all the code in the cycle is inter-dependent. While it might look like the code in the different packages has separate functions, in essence all the code in the cycle acts like one big package.

    Rule logic

    Builds the package dependency graph, in which each package is a graph node, and each function call from one package to another is an edge. The edges are directional, pointing from the caller package to the callee package.

    A graph traversal finds cycles - a cycle being a path which starts with a package (a node), traverses through other packages (via edges), and returns to the original package.

    For each package cycle that’s detected in the call graph, the rule then searches for a sequence of function calls that matches the cycle. This sequence of events is returned in the finding.

    Notes

    There may be multiple paths through the event trace that produce a given package cycle. Only one of these paths is reported in the finding.

    Resolution

    If a package in the circular dependency is designed to call back into the code that call it, it can be added to the ignoredPackages list. This is common with helper and middleware code.

    Otherwise, you can fix the cyclic dependency by refactoring the code. One way to do this is to refactor some of the code into a new package, class, or library.

    Options

    • depth. Minimum number of packages in a path that will be reported. Default: 4.
    • ignoredPackages: MatchPatternConfig[]. Packages which match this pattern are not included in the dependency graph. Default: empty - including all packages.

    Examples

    - rule: circularDependency
      properties:
        depth: 4 # default
        ignoredPackages:
          - equal: activesupport
          - equal: app/helpers
    

  • Deprecated crypto algorithm

    • Id
    • deprecated-crypto-algorithm
    • Impact Domain
    • Security
    • Scope
    • root

    Ensure that cryptographic operations do not use deprecated algorithms.


  • Deserialization of untrusted data

    • Id
    • deserialization-of-untrusted-data
    • Impact Domain
    • Security
    • Scope
    • http_server_request

    Finds occurrances of deserialization in which the mechanism employed is known to be unsafe, and the data comes from an untrusted source and hasn’t passed through a sanitization mechanism.

    Rule logic

    Finds all events labeled deserialize.unsafe that receive tainted data (as determined by object identity or string value) as an input.

    For each of these events; checks if all the inputs have been sanitized.

    Data that has been passed to a function labeled deserialize.sanitize is assumed to be sanitized from this point onwards. Such a function could either check the value is sanitized (note no verification is currently done to ensure this result is checked) or return the transformed value after any necessary sanitization.

    Data passed to a function labeled deserialized.safe is considered in all functions called by it (down the callstack). Functions that first sanitize data and then use an unsafe deserialization function should carry this label.

    The set of tracked tainted data initially includes the HTTP message parameters and is expanded to include any non-primitive (ie. longer than 5 characters) observed outputs of functions that consume tainted data.

    The reliability of this rule now depends on completeness of the AppMap. If there is a data transformation that is not captured it’s invisible to the rule and will result in failure to associate it with the tracked untrusted data.

    Notes

    With insecure deserialization, it is usually possible for an attacker to craft a malicious payload that executes code shortly after deserialization.

    Resolution

    Consider if the library you’re using offers a safe deserialization function variant that you can use instead. Using unsafe functions is only rarely needed and typically requires a good reason.

    If you need to use the unsafe function, make sure you’re able to handle unexpected input safely. Sanitize the data thoroughly first; label the sanitization function with deserialize.sanitize label or wrap the whole sanitization and deserialization logic in a function labeled deserialize.safe.

    If you need to deserialize untrusted data, JSON is often a good choice as it is only capable of returning ‘primitive’ types such as strings, arrays, hashes, numbers and nil. If you need to deserialize other classes, you should handle this manually. Never deserialize to a user specified class¹.

    Ensure that the JSON library provided by your language and framework does not perform unsafe deserialization.

    1. https://docs.ruby-lang.org/en/3.0/doc/security_rdoc.html

    Options

    None

    Examples

    - rule: deserializationOfUntrustedData
    

  • Exec of untrusted command

    • Id
    • exec-of-untrusted-command
    • Impact Domain
    • Security
    • Scope

    Find occurrances of system command execution in which the command string is not guaranteed to be safe.

    Rule logic

    Find all events labeled system.exec that are not a descendant of an event labeled system.exec.safe. For each of these events, all event parameters are checked.

    Each parameter whose type is string or object is verified to ensure that it’s trusted. For data to be trusted, it must be the return value of a function labeled system.exec.sanitize.

    Resolution

    If you can guarantee that you are using system command execution in a safe way, but it’s not possible to obtain the raw data from a function labeled system.exec.sanitize, you can wrap the system command in a function labeled system.exec.safe.

    Options

    None

    Examples

    - rule: execOfUntrustedCommand
    

  • HTTP 500

    • Id
    • http-500
    • Impact Domain
    • Stability
    • Scope
    • http_server_request
    • Labels

    Identifies when an HTTP server request has returned a 500 status code. HTTP 500 status code generally indicate an unanticipated problem in the backend that is not handled in a predictable way. 500 status codes are also hard for client code to handle, because they don’t indicate any particular problem or suggest a solution.

    Rule logic

    An HTTP 500 status code that’s returned by an HTTP server request will be emitted as a finding by this rule.

    Resolution

    The execution trace of request may show an unhandled exception. Or it may show exception or error handling that failed in some way, and was caught and handled generically by the framework. Use the trace to figure out the root cause of the problem, and update the code to report the problem using a more informative HTTP status code.

    Options

    None

    Examples

    - rule: http500
    

  • Illegal package dependency

    • Id
    • illegal-package-dependency
    • Impact Domain
    • Maintainability
    • Scope
    • command
    • Labels

    Ensures that all calls to a specified callee package come from an approved caller package. This is a way of defining and enforcing an architectural constraint that may not be provided by the programming language itself.

    Rule logic

    All packages which call the calleePackage are inspected. Each one must match one of the callerPackage options.

    Notes

    Many programming languages do not provide a way to make a package “private” or “protected” in the same way as a class or function. Yet, it’s often desirable to limit the places from which code in a certain package can be called. This rule provides a way to define and enforce this type of architectural constraint.

    Resolution

    The code which is illegally calling into the calleePackage should be refactored to call one of the allowed callerPackages instead. If the needed functionality is not available on a callerPackage, then one of the callerPackages should be modified to provide it.

    Options

    • callerPackages: MatchPatternConfig[]. Packages which are allowed to call the calleePackage. Required.
    • calleePackage: MatchPatternConfig. Package whose callers should be checked. Required.

    Examples

    - rule: illegalPackageDependency
      properties:
        callerPackages:
          - equal: actionpack
        calleePackage:
          equal: app/controllers
    

  • Incompatible HTTP client request

    • Id
    • incompatible-http-client-request
    • Impact Domain
    • Stability
    • Scope
    • http_client_request
    • Labels
    • References

    Detects HTTP client requests which are incompatible with a published OpenAPI schema.

    Rule logic

    Each HTTP client request is converted to an OpenAPI schema document. This is done by examining the request method, request URI, parameters, body, headers, etc. and representing them as OpenAPI. Then, the client OpenAPI schema is compared to the published server OpenAPI schema. If any breaking changes are detected between the client request and the published server schema, these are reported as findings.

    Resolution

    Modify the HTTP client request to conform to the published schema.

    Options

    • schemata: Record<string, string> A map from server hostnames to schema URLs. A schema must be provided for each server hostname that’s invoked in the AppMap.

    Examples

    - rule: incompatibleHttpClientRequest
      parameters:
        schemata:
          'myserver:8080': https://github.com/mycorp/myserver/tree/main/openapi.yaml
    

  • Insecure compare

    • Id
    • insecure-compare
    • Impact Domain
    • Security
    • Scope

    Identifies cases in which secrets are being compared directly using string.equals.

    Ordinary string comparison of user-provided data with a piece of secret data can leak information about the secret through timing attacks, because of short-circuting (returning false on first mismatch). This can allow the attacker to significantly speed up brute forcing, turning an intractable exponential problem into a linear one.

    Rule logic

    The rule looks for events labeled secret and string.equals.

    On encountering an event labeled secret it remembers the return value.

    On encountering string.equals it looks at the arguments and the receiver. If any of the arguments is a previously seen secret, or matches a list of known secret-like regular expressions, the comparison is flagged as insecure, unless any of the arguments is a BCrypt digest.

    Notes

    When generating appmaps, ensure that string comparison functions (such as String#== in Ruby and String.equals in Java) are traced and correctly labeled with string.equals. Any functions you know to return a secret (eg. a model accessor for an API key) should be labeled secret.

    Since using this rule generally requires labeling all string comparisons its use is currently limited due to performance and space overhead of tracing them: string comparisons are commonly used throughout the code base and libraries.

    It’s advisable to only trace string equality on a limited subset of tests (perhaps the ones known to touch secret related functionality); alas, this is not something easily attainable with current AppMap recorders and requires swapping or modifying configuration files.

    Resolution

    To fix this issue, either hash values before comparing or use a constant-time comparison in such operations. Constant-time comparison functions always compare every character of the string, removing the timing side channel. You can usually find functions like this in cryptographic and utility libraries, eg. ActiveSupport::SecurityUtils.secure_compare.

    Options

    None

    Examples

    - rule: insecureCompare
    

  • Job not cancelled

    • Id
    • job-not-cancelled
    • Impact Domain
    • Stability
    • Scope
    • transaction

    Finds jobs which are created in a transaction, and not cancelled when the transaction is rolled back.

    Rule logic

    THe rule identifies SQL transaction boundaries by examining the SQL queries for START TRANSACTION, ROLLBACK, COMMIT, etc.

    Within each transaction, the rule looks for events labeled job.create. If the transaction is rolled back, and there is not a corresponding event labeled job.cancel, then a finding is reported.

    Notes

    It’s recommended to program delayed jobs defensively to check for data and silently do nothing if that data is missing (eg. due to a rollback or a duplicate job); job details in this design are stored in the database and the queue entries only reference them.

    This rule is designed for use when this practice is impossible or not followed, and with external job queues that do not automatically roll back with the transaction. If the job queue is the database and the same connection is used for the job queue and for the request, then this check is not needed.

    Resolution

    Cancel any queued jobs when the transaction rolls back.

    Options

    None

    Examples

    - rule: jobNotCanceled
    

  • Jwt algorithm none

    • Id
    • jwt-algorithm-none
    • Impact Domain
    • Security
    • Scope

    Finds usage of unsecured JWTs which use the none algorithm. When declaring this algorithm, there is no signature contained within the token that may be cryptographically verified. As a result, the data encoded within the token may be easily forged.

    Rule logic

    Any function which encodes a new JWT will have its return value checked for presence of the none algorithm within the token header.

    Options

    None

    Examples

    - rule: jwt-algorithm-none
    

  • Jwt unverified signature

    • Id
    • jwt-unverified-signature
    • Impact Domain
    • Security
    • Scope

    Finds cases where a JWT is decoded but the signature is never verified. Without proper signature verification, the service will unknowingly accept arbitrary token payloads from any origin.

    Rule logic

    Following a function call to decode a JWT, a subsequent function call to verify the token signature is expected.

    Options

    None

    Examples

    - rule: jwt-unverified-signature
    

  • Logout without session reset

    • Id
    • logout-without-session-reset
    • Impact Domain
    • Security
    • Scope
    • http_server_request

    Determines when a user has been logged out from the application, but the session hasn’t been cleared. When the session isn’t cleared after logout, the session is vulnerable to a session fixation attack.

    Rule logic

    Iterates over all descendants of the HTTP server request. If an event labeled security.logout is encountered, the event must have a descendant labeled http.session.clear, otherwise a finding is emitted.

    Notes

    Return values from security.logout and http.session.clear are not checked, as these methods are assumed to always succeed.

    Options

    None

    Examples

    - rule: logoutWithoutSessionReset
    

  • Missing authentication

    • Id
    • missing-authentication
    • Impact Domain
    • Security
    • Scope
    • http_server_request

    An HTTP server request is missing authentication. In this case, the request may be serving assets that should be protected by authentication - but no authentication is actually happening.

    Rule logic

    This rule checks all HTTP server requests that satisfy the following conditions:

    • HTTP status code is < 300
    • Matches include and exclude lists of content type (by default, these are empty).

    For each matching request, any event that satisfies either of these conditions will satisfy the rule:

    1. Has label access.public.
    2. Has label security.authentication, and returns a truthy value.

    Notes

    If a request does not require an authenticated user (e.g. because it contains completely public information), then this rule can be satisfied by calling any function labeled access.public.

    If the security.authentication event returns a falsey value (false, null, etc), then authentication is assumed to be denied, and the rule is not satisfied.

    Resolution

    If the request is designed to be public, and the omission of authentication is intentionaly, modify the code so that it calls a function labeled access.public.

    Otherwise, modify the code so that it calls a function labeled security.authentication which returns a truthy result (for example, a User object).

    Options

    Examples

    - rule: missingAuthentication
      properties:
        includeContentTypes:
          - match: ^application/json
    

  • Missing content type

    • Id
    • missing-content-type
    • Impact Domain
    • Stability
    • Scope
    • http_server_request
    • Labels
    • References

    Finds HTTP server requests that don’t provide a Content-Type header in the response.

    Rule logic

    Every HTTP server request is checked. If the status code indicates redirect or “No content”, then the rule passes. Otherwise, a finding is issued if the response is missing a Content-Type header.

    Notes

    When a response is missing the Content-Type header, it’s unclear to clients how to handle the response data. Bugs are likely to result.

    Resolution

    Provide a Content-Type in the response.

    Options

    None

    Examples

    - rule: missingContentType
    

  • N plus one query

    • Id
    • n-plus-one-query
    • Impact Domain
    • Performance
    • Scope
    • command
    • Labels

    Finds occurrences of a query being repeated within a loop.

    Rule logic

    Within each command, SQL queries are normalized, grouped, and counted.

    If the number of duplicate instances of a normalized query exceeds the threshold, it’s reported as a finding.

    Notes

    N plus one queries typically occur when a data access object (DAO) has a one-to-many or many-to-many relationship, and the relationship is enumerated within a loop. The DAO will issue a separate query to fetch each related record. If the number of related objects is large, or if each one is fairly expensive to fetch, application performance suffers.

    Resolution

    DAO libraries typically offer a feature called “eager loading”. For example:

    Enable eager loading on the association in question to fetch the data efficiently, without repeated, identical queries.

    Options

    • warningLimit Threshold for reporting a warning. Default: 5.
    • errorLimit Threshold for reporting an error. Default: 10.

    Examples

    - rule: nPlusOneQuery
      parameters:
        warningLimit: 5
        errorLimit: 10
    

  • Query from invalid package

    • Id
    • query-from-invalid-package
    • Impact Domain
    • Maintainability
    • Scope
    • Labels

    Ensures that SQL queries are made only from an approved list of packages. This helps to make the code more maintainable by encapsulating access to the database.

    Notes

    When too many packages are performing direct SQL queries, it’s very hard to keep the code modular. The result is a lack of coherent design and degredation in maintainability.

    Rule logic

    All functions which make SQL queries are inspected. Each one must match one of the allowedPackages.

    Resolution

    The code which is making the direct query should be refactored to use the database through one of the allowed packages.

    Options

    • allowedPackages: MatchPatternConfig[]. Packages which are allowed to make queries. Required.
    • allowedQueries: MatchPatternConfig[]. Queries which are allowed from anywhere. Default: [/\bBEGIN\b/i, /\bCOMMIT\b/i, /\bROLLBACK\b/i, /\bRELEASE\b/i, /\bSAVEPOINT\b/i].

    Examples

    - rule: queryFromInvalidPackage
      properties:
        callerPackages:
          - equal: actionpack
        calleePackage:
          equal: app/controllers
    

  • Query from view

    • Id
    • query-from-view
    • Impact Domain
    • Maintainability
    • Scope
    • Labels

    Ensures that SQL queries are not performed directly from the view layer. This helps to make the code more maintainable by encapsulating access to the database.

    Notes

    Performing SQL queries directly from the view layer introduces several maintainability concerns:

    1. View logic is tied to the server, and cannot be refactored to the client side.
    2. Database interactions are harder to test, because they depend on details of the view implementation.
    3. Performance can be adversely and unexpectedly affected by minor changes to the view.

    Rule logic

    Each query is tested to see if it has an ancestor event with the view label.

    Resolution

    Data objects which are passed to the view layer for rendering should not have access to the database. Disable database access in some way, or transfer data from DAO objects into plain old structs.

    Options

    • forbiddenLabel. Label which identifies the view layer. Default: mvc.template.

    Examples

    - rule: queryFromView
      properties:
        forbiddenLabel: mvc.template
    

  • RPC without circuit breaker

    • Id
    • rpc-without-circuit-breaker
    • Impact Domain
    • Stability
    • Scope
    • References

    Identifies HTTP client requests which do not utilize a circuit breaker.

    Rule logic

    Each HTTP client request is expected to have a descendant labeled with the expected label.

    Notes

    Use the circuit breaker pattern in microservices architecture to make system behavior more predictable when a service becomes overloaded or unavailable.

    Resolution

    Utilize a circuit breaker library - your organization may have a specific preference.

    Some examples:

    Options

    • expectedLabel. Label which identifies the circuit breaker function. Default: rpc.circuit_breaker.

    Examples

    - rule: rpcWithoutCircuitBreaker
      properties:
        expectedLabel: rpc.circuit_breaker
    

  • Save without validation

    • Id
    • save-without-validation
    • Impact Domain
    • Stability
    • Scope
    • Labels

    Ensures that data saved by data access object is validated first.

    Rule logic

    Finds events whose method name is save or save!. Then verifies that each of these events has a descendant whose method name is valid? or validate!.

    Notes

    In a future revision, this rule will be refactored to use labels rather than method names.

    Resolution

    Ensure that data is validated before being saved; for example, using a before_save hook.

    Options

    None

    Examples

    - rule: saveWithoutValidation
    

  • Secret in log

    • Id
    • secret-in-log
    • Impact Domain
    • Security
    • Scope
    • root

    Identifies when a known or assumed secret is written to a log. Logs are often transported into other systems that are treated with lesser security - such as backups. Therefore, secrets written into log files are more likely to be leaked or discovered by cyber-attackers.

    Rule logic

    Operation of this rule depends on two labels: secret and log. A function labeled secret is assumed to return a secret value - this rule keeps a running tally of all the secrets created in an AppMap. When a function labeled log is called, the rule looks at the log message, and checks whether any of the known secrets are in it.

    The log message is also tested against a list of known regular expressions that are likely to match secrets.

    Notes

    Be sure and apply the secret label to any function in your code base that generates a secret (such as encryption keys, user tokens, API keys, reset tokens, etc.).

    Resolution

    If the log message is written by code that you control, the simplest resolution is to remove the log statement - or to remove the secret from the log message.

    If the log message is not controlled by you (it’s generated by a framework), your choices are more limited. You could open a pull request with the framework, or you can change the log level to suppress the offending message.

    Options

    None

    Examples

    - rule: secretInLog
    

  • Slow function call

    • Id
    • slow-function-call
    • Impact Domain
    • Performance
    • Scope
    • Labels
    • References

    Ensures that function elapsed time does not exceed a threshold.

    Rule logic

    Checks all configured functions to see if the elapsed time exceeds the configured threshold.

    Notes

    This rule is most useful when applied to code that is specifically designed to test application performance.

    Resolution

    Optimize the function elapsed time using a profiler, SQL tuning, etc.

    Options

    • functions: MatchPatternConfig[] list of functions to check. Required.
    • timeAllowed max time (in seconds) allowed for the function.

    Examples

    - rule: slowFunctionCall
      properties:
        timeAllowed: 0.25
        functions:
          - match: ^app/models
          - match: ^app/jobs
    

  • Slow HTTP server request

    • Id
    • slow-http-server-request
    • Impact Domain
    • Performance
    • Scope
    • http_server_request
    • Labels
    • References

    Ensures that HTTP server request elapsed time does not exceed a threshold.

    Rule logic

    Checks HTTP server requests to see if the elapsed time exceeds the configured threshold.

    Notes

    This rule is most useful when applied to code that is specifically designed to test application performance.

    Resolution

    Optimize the request elapsed time using a profiler, SQL tuning, etc.

    Options

    • timeAllowed max time (in seconds) allowed for the request.

    Examples

    - rule: slowHttpServerRequest
      properties:
        timeAllowed: 0.25
    

  • Slow query

    • Id
    • slow-query
    • Impact Domain
    • Performance
    • Scope
    • Labels
    • References

    Ensures that SQL query elapsed time does not exceed a threshold.

    Rule logic

    Checks all configured queries to see if the elapsed time exceeds the configured threshold.

    Notes

    This rule is most useful when applied to code that is specifically designed to test application performance.

    Resolution

    Optimize the elapsed time using SQL tuning.

    Options

    • timeAllowed max time (in seconds) allowed for the query.

    Examples

    - rule: slowQuery
      properties:
        timeAllowed: 0.25
    

  • Too many joins

    • Id
    • too-many-joins
    • Impact Domain
    • Performance
    • Scope
    • Labels

    Verifies that the number of joins in SQL queries does not exceed a threshold.

    Rule logic

    Counts the number of joins in each SQL query. If the count exceeds the configured threshold, a finding is reported.

    Notes

    Queries with too many joins often have poor or unpredictable performance.

    Resolution

    Having multiple joins may be legitimate - but it is a situation that merits a closer look, especially when the query is generated by an ORM.

    Take a look at a query plan from a database that has a realistically high volume of data, and verify that the query can be executed efficiently.

    Options

    • warningLimit the maximum number of joins allowed.

    Examples

    - rule: tooManyJoins
      properties:
        warningLimit: 5
    

  • Too many updates

    • Id
    • too-many-updates
    • Impact Domain
    • Maintainability
    • Scope
    • command
    • Labels

    Verifies that the number of SQL and RPC updates performed by a command does not exceed a threshold.

    Rule logic

    Counts the number of SQL and RPC updates in each command. A SQL update is any INSERT or UPDATE query. An RPC update is an HTTP client request that uses PUT, POST, or PATCH.

    If the number of updates exceeds the threshold, a finding is reported.

    Notes

    As a codebase evolves, sometimes a request can start to make more and more SQL and RPC updates.There are several negative repercussions of this:

    1. It’s no longer clear to a developer what the primary responsibility of the command is.
    2. The command becomes more likely to fail - resulting in a rollback of all the updates, or possibly leaving the system in an inconsistent state.
    3. The performance of the command degrades as it does more and more work.

    Resolution

    Consider refactoring the command into multiple commands.

    Schedule a job to perform some of the work offline.

    Options

    • warningLimit the maximum number of joins allowed.

    Examples

    - rule: tooManyUpdates
      properties:
        warningLimit: 20
    

  • Unauthenticated encryption

    • Id
    • unauthenticated-encryption
    • Impact Domain
    • Security
    • Scope

    Ensures that encryption operations use authenticated encryption.

    Rule logic

    Finds all events labeled crypto.encrypt. For each of these events, there should be another event in the same AppMap that has the same receiver.object_id and also has the label crypto.set_auth_data.

    Notes

    OWASP recommends against the use of unauthenticated encryption.

    Resolution

    Change the encryption code to use a current authenticated encryption algorithm. At the time of this writing, an example is aes-256-gcm.

    Examples:

    Options

    None

    Examples

    - rule: unauthenticated-encryption
    

  • Unbatched materialized query

    • Id
    • unbatched-materialized-query
    • Impact Domain
    • Performance
    • Scope

    Finds large data sets that are queried from the database and loaded into memory.

    Rule logic

    Examines all SQL SELECT queries (as opposed to insert/update). If the query satisfies any of the following conditions:

    • Has a LIMIT clause
    • Has a COUNT clause at the top level
    • Queries only for metadata (sqlite_master table)

    then the query is skipped.

    Otherwise, the rule checks to see if the query has an ancestor labeled dao.materialize. If so, it’s emitted as a finding.

    Notes

    Materializing large amounts of data code objects is a frequent cause of poor performance and memory exhaustion.

    A COUNT or LIMIT clause is a good indication that the code is taking steps to limit the amount of data that’s loaded into memory.

    Resolution

    If data is being loaded into memory from an un-LIMITed query:

    • Consider whether the data processing that’s being performed in-memory can be performed in the database - either via SQL or a stored procedure.
    • If the data is being loaded solely for presentation purposes, fetch data in batches - e.g. with a pagination library.

    Options

    None

    Examples

    - rule: unbatchedMaterializedQuery
    

  • Unfulfilled promise

    • Id
    • unfulfilled-promise
    • Impact Domain
    • Stability
    • Scope
    • Labels
    • References

    Finds promises which have been created during the recording but have remained unfulfilled at the end.

    Rule logic

    The rule simply looks for return events with value of Promise { <pending> } without a subsequent update.

    Notes

    Promise { <pending> } is a special value used by the appmap-node agent to represent promises that haven’t been fulfilled yet. Normally, once the promise is fulfilled, an event update is added to the AppMap with the resolved value and total elapsed run time.

    However, if a promise remains unfulfilled when the recording ends (for example when a HTTP response is sent or a test case finishes) this pending state is never updated.

    Most of the time it means some asynchronous computation has been started and its results not awaited for and therefore not collected; such computations should be removed or the results awaited.

    In some cases this is an intended behaviour; for example, a background book-keeping or cleanup process might be started which doesn’t directly impact the results of the operation that triggered it. Note that during testing such processes should still run to completion before a test case finishes (or else be suppressed altogether); otherwise there might be unintended interference between test cases leading to brittle tests. Each test case should start from a known, clean and quiescent environment.

    Resolution

    Identify where the promise is created and make sure to await on it. Even when the result is void, some other part of the program might assume the asynchronous computation has completed. Without awaiting it at that point a race condition can result, leading to intermittent stability issues.

    Options

    None

    Examples

    - rule: unfulfilledPromise
    

  • Update in get request

    • Id
    • update-in-get-request
    • Impact Domain
    • Maintainability
    • Scope
    • http_server_request
    • References

    Finds SQL updates that are performed in an HTTP server GET request.

    Rule logic

    Checks each HTTP server GET and HEAD request. Within each of these requests, checks for SQL queries that match the queryInclude option and don’t match queryExclude. If any such queries exist, they are emitted as findings.

    Notes

    Performing data updates in a GET request is anti-pattern, and counter to the intent of HTTP. For data modifications, use PUT, POST, or PATCH.

    Data updates which are used for the purposes of tracking user activity are fine in any type of request. Use the queryExclude option to allow these queries.

    Resolution

    Perform data updates in PUT, POST, or PATCH requests.

    Options

    • queryInclude: RegExp[]. Default: [/\binsert\b/i, /\bupdate\b/i].
    • queryExclude: RegExp[]. Default: empty.

    Examples

    - rule: updateInGetRequest
      properties:
        queryExclude:
          - /\bINSERT\b/i
          - /\bUPDATE\b/i
    


Was this page helpful? thumb_up Yes thumb_down No
Thank you for your feedback!