diff --git a/Document/0x04b-Mobile-App-Security-Testing.md b/Document/0x04b-Mobile-App-Security-Testing.md index 7d3e7a40f4..3b5defaa6c 100644 --- a/Document/0x04b-Mobile-App-Security-Testing.md +++ b/Document/0x04b-Mobile-App-Security-Testing.md @@ -133,7 +133,21 @@ When no data classification policy is available, use the following list of infor - any data whose protection is a legal obligation - any technical data generated by the app (or its related systems) and used to protect other data or the system itself (e.g., encryption keys) - A definition of "sensitive data" must be decided before testing begins because detecting sensitive data leakage without a definition may be impossible. +A definition of "sensitive data" must be decided before testing begins because detecting sensitive data leakage without a definition may be impossible. + +##### Identifying Security-Relevant Contexts in Code + +When developing a mobile application, it's crucial to accurately identify and handle security-relevant contexts within the codebase. These contexts typically involve operations such as authentication, encryption, and authorization, which are often the target of security attacks. Incorrect implementation of cryptographic functions in these areas can lead to significant security vulnerabilities. + +Properly distinguishing security-relevant contexts helps in minimizing false positives during security testing. False positives can divert attention from real issues and waste valuable resources. Here are some common scenarios: + +- **Random Number Generation**: Using weak random number generators can be a serious security flaw in contexts like authentication or encryption key generation. However, not all uses of random numbers are security-sensitive. For instance, using a less robust random number generator for non-security purposes like shuffling a list of items in a game is generally acceptable. + +- **Hashing**: Hashing is often used in security for storing passwords or ensuring data integrity. However, hashing a non-sensitive value, like a device's screen resolution for analytics, isn't a security concern. + +- **Encryption vs Encoding**: A common misunderstanding is conflating encoding (like Base64) with encryption. Base64 encoding is not a secure method for protecting sensitive data as it's easily reversible. It's crucial to recognize when data requires actual encryption (for confidentiality) versus when it's being encoded for compatibility or formatting reasons (like encoding binary data into a text format for transmission). Misinterpreting encoding as a security measure can lead to overlooking actual encryption needs for sensitive data. + +- **API Token Storage**: Storing API tokens or keys in plain text within the app's code or in insecure locations (like SharedPreferences on Android or UserDefaults on iOS) is a common security mistake. However, if the token is for a non-sensitive, read-only public API, this might not be a security risk. Contrast this with storing a token for a sensitive or write-access API, where improper storage would be a significant security concern. #### Intelligence Gathering diff --git a/mkdocs.yml b/mkdocs.yml index e0de58649e..1e86220edf 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,6 +6,8 @@ edit_uri: "" # disable edit button nav: - Home: index.md + - "": + - ... | MASWE/**/*.md - MASTG: - MASTG/index.md - Intro: diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/test.md b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/test.md index 268c6713ed..8e745077bd 100644 --- a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/test.md +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-insecure-random-use/test.md @@ -19,10 +19,8 @@ Android apps sometimes use insecure pseudorandom number generators (PRNGs) such ## Observation -The output should contain a **list of locations where insecure random APIs are used**. +The output should contain a list of locations where insecure random APIs are used. ## Evaluation -Inspect the app source code using the provided location information. - The test case fails if you can find random numbers generated using those APIs that are used in security-relevant contexts. diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/test.md b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/test.md index 314ebdb171..1b3091fb26 100644 --- a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/test.md +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/android-non-random-use/test.md @@ -19,10 +19,8 @@ Android applications sometimes use non-random sources to generate "random" value ## Observation -The output should contain a **list of locations where non-random sources are used**. +The output should contain a list of locations where non-random sources are used. ## Evaluation -Inspect the app source code using the provided location information. - The test case fails if you can find security-relevant values, such as passwords or tokens, generated using non-random sources. diff --git a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/risk.md b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/risk.md index d3ff8ca03d..bff0eb0dff 100644 --- a/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/risk.md +++ b/risks/MASVS-CRYPTO/1-strong-crypto/insecure-random/risk.md @@ -4,10 +4,10 @@ alias: insecure-random platform: ["android", "ios"] profiles: ["L1", "L2"] mappings: -- masvs-v1: [MSTG-CRYPTO-6] -- masvs-v2: [MASVS-CRYPTO-1] -- cwe: [338, 337] -- android: https://developer.android.com/privacy-and-security/risks/weak-prng + masvs-v1: [MSTG-CRYPTO-6] + masvs-v2: [MASVS-CRYPTO-1] + cwe: [338, 337] + android: https://developer.android.com/privacy-and-security/risks/weak-prng observed_examples: - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-6386 - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-3419 diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/MastgTest.kt b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/MastgTest.kt index 5767b9e7dc..52d67982d5 100644 --- a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/MastgTest.kt +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/MastgTest.kt @@ -12,9 +12,7 @@ import java.util.logging.Logger class MastgTest (private val context: Context){ - fun mastgTest(): String { - - // Requires: + fun mastgTest(): String { val SENSITIVE_DATA = mapOf( "precise_location_latitude" to "37.7749", @@ -48,12 +46,13 @@ class MastgTest (private val context: Context){ outputStream.close() val responseCode = httpURLConnection.responseCode + val responseContent = httpURLConnection.inputStream.bufferedReader().readText() if (responseCode == HttpURLConnection.HTTP_OK) { Log.d("HTTP_SUCCESS", "Successfully authenticated.") } else { Log.e("HTTP_ERROR", "Failed to authenticate. Response code: $responseCode") } - result = "$responseCode\n\n$postData" + result = "$responseCode\n\n$responseContent" } catch (e: Exception) { e.printStackTrace() diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/MastgTest_reversed.java b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/MastgTest_reversed.java new file mode 100644 index 0000000000..33ab22d1a2 --- /dev/null +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/MastgTest_reversed.java @@ -0,0 +1,90 @@ +package org.owasp.mastestapp; + +import android.content.Context; +import android.util.Log; +import androidx.autofill.HintConstants; +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import kotlin.Metadata; +import kotlin.TuplesKt; +import kotlin.collections.CollectionsKt; +import kotlin.collections.MapsKt; +import kotlin.jvm.internal.Intrinsics; +import kotlin.jvm.internal.Ref; + +/* compiled from: MastgTest.kt */ +@Metadata(d1 = {"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0002\u0010\u0004J\u0006\u0010\u0005\u001a\u00020\u0006R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\u0007"}, d2 = {"Lorg/owasp/mastestapp/MastgTest;", "", "context", "Landroid/content/Context;", "(Landroid/content/Context;)V", "mastgTest", "", "app_debug"}, k = 1, mv = {1, 9, 0}, xi = 48) +/* loaded from: classes4.dex */ +public final class MastgTest { + public static final int $stable = 8; + private final Context context; + + public MastgTest(Context context) { + Intrinsics.checkNotNullParameter(context, "context"); + this.context = context; + } + + /* JADX WARN: Multi-variable type inference failed */ + public final String mastgTest() { + final Map SENSITIVE_DATA = MapsKt.mapOf(TuplesKt.to("precise_location_latitude", "37.7749"), TuplesKt.to("precise_location_longitude", "-122.4194"), TuplesKt.to(HintConstants.AUTOFILL_HINT_NAME, "John Doe"), TuplesKt.to("email_address", "john.doe@example.com"), TuplesKt.to("phone_number", "+11234567890"), TuplesKt.to("credit_card_number", "1234 5678 9012 3456")); + final Ref.ObjectRef result = new Ref.ObjectRef(); + result.element = ""; + Thread thread = new Thread(new Runnable() { // from class: org.owasp.mastestapp.MastgTest$$ExternalSyntheticLambda0 + @Override // java.lang.Runnable + public final void run() { + MastgTest.mastgTest$lambda$1(SENSITIVE_DATA, result); + } + }); + thread.start(); + thread.join(); + return (String) result.element; + } + + /* JADX INFO: Access modifiers changed from: private */ + /* JADX WARN: Type inference failed for: r7v10, types: [T, java.lang.String] */ + public static final void mastgTest$lambda$1(Map SENSITIVE_DATA, Ref.ObjectRef result) { + Intrinsics.checkNotNullParameter(SENSITIVE_DATA, "$SENSITIVE_DATA"); + Intrinsics.checkNotNullParameter(result, "$result"); + try { + URL url = new URL("https://httpbin.org/post"); + URLConnection openConnection = url.openConnection(); + Intrinsics.checkNotNull(openConnection, "null cannot be cast to non-null type java.net.HttpURLConnection"); + HttpURLConnection httpURLConnection = (HttpURLConnection) openConnection; + httpURLConnection.setRequestMethod("POST"); + httpURLConnection.setDoOutput(true); + httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + Collection destination$iv$iv = new ArrayList(SENSITIVE_DATA.size()); + for (Map.Entry item$iv$iv : SENSITIVE_DATA.entrySet()) { + String key = (String) item$iv$iv.getKey(); + String value = (String) item$iv$iv.getValue(); + destination$iv$iv.add(URLEncoder.encode(key, "UTF-8") + '=' + URLEncoder.encode(value, "UTF-8")); + url = url; + } + String postData = CollectionsKt.joinToString$default((List) destination$iv$iv, "&", null, null, 0, null, null, 62, null); + BufferedOutputStream outputStream = new BufferedOutputStream(httpURLConnection.getOutputStream()); + BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8")); + bufferedWriter.write(postData); + bufferedWriter.flush(); + bufferedWriter.close(); + outputStream.close(); + int responseCode = httpURLConnection.getResponseCode(); + if (responseCode == 200) { + Log.d("HTTP_SUCCESS", "Successfully authenticated."); + } else { + Log.e("HTTP_ERROR", "Failed to authenticate. Response code: " + responseCode); + } + result.element = responseCode + "\n\n" + postData; + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/demo.md b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/demo.md index 9a2d20d8f5..a12186b1dd 100644 --- a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/demo.md +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/demo-1/demo.md @@ -7,36 +7,40 @@ code: [kotlin] ### Sample -{{ MastgTest.kt }} +The snippet below shows sample code that sends sensitive data over the network using the `HttpURLConnection` class. The data is sent to `https://httpbin.org/post` which is a dummy endpoint that returns the data it receives. + +{{ MastgTest.kt # MastgTest_reversed.java }} ### Steps -1. Start the device, in this case, the Android emulator: +Start the device, in this case, the Android emulator: ```bash emulator -avd Pixel_3a_API_33_arm64-v8a -writable-system ``` -2. Run mitmproxy with the custom script for logging sensitive data and dump the relevant traffic to a file. +Run mitmproxy with the custom script for logging sensitive data and dump the relevant traffic to a file. + +Note that the script is preconfigured with data that's already considered sensitive for this application. When running this test in a real-world scenario, you should determine what is considered [sensitive data](../../../../../../Document/0x04b-Mobile-App-Security-Testing.md#identifying-sensitive-data "Sensitive Data") based on the app's privacy policy and relevant privacy regulations. One recommended way to do this is by checking the app's privacy policy and the App Store Privacy declarations. {{ mitm_sensitive_logger.py }} {{ run.sh }} -3. Launch the app from Android Studio and click the button in the app. +Launch the app from Android Studio and click the button which will send the sensitive data over the network. The script will capture the network traffic and log the sensitive data. ### Observation -The script has identified several instances in the network traffic where sensitive data is sent. +The script has identified several instances of sensitive data in the network traffic. + +- The first instance is a POST request to `https://httpbin.org/post` which contains the sensitive data values in the request body. +- The second instance is a response from `https://httpbin.org/post` which contains the sensitive data values in the response body. {{ sensitive_data.log }} ### Evaluation -Review each of the reported instances. - -- The first instance is a POST request to `https://httpbin.org/post` which contains the sensitive data values in the request body. -- The second instance is a response from `https://httpbin.org/post` which contains the sensitive data values in the response body. +After reviewing the captured network traffic, we can conclude that the test fails because the sensitive data is sent over the network. This is a dummy example, but in a real-world scenario, you should determine which of the reported instances are privacy-relevant and need to be addressed. diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/test.md b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/test.md index ffcbdda91e..da7b2f96aa 100644 --- a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/test.md +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/android-data-in-traffic-capture/test.md @@ -12,18 +12,20 @@ prerequisites: Attackers may capture network traffic from Android devices using an intercepting proxy, such as [OWASP ZAP](https://www.zaproxy.org/), [Burp Suite](https://portswigger.net/burp), or [mitmproxy](https://mitmproxy.org/), to analyze the data being transmitted by the app. This works even if the app uses HTTPS, as the attacker can install a custom root certificate on the Android device to decrypt the traffic. Inspecting traffic that is not encrypted with HTTPS is even easier and can be done without installing a custom root certificate for example by using [Wireshark](https://www.wireshark.org/). +The goal of this test is to verify that sensitive data is not being sent over the network, even if the traffic is encrypted. This test is especially important for apps that handle sensitive data, such as financial or health data, and should be performed in conjunction with a review of the app's privacy policy and the App Store Privacy declarations. + ## Steps 1. Start the device. - 2. Start [logging sensitive data from network traffic](../../../../../techniques/android/MASTG-TECH-0100.md). - 3. Launch and use the app going through the various workflows while inputting sensitive data wherever you can. Especially, places where you know that will trigger network traffic. ## Observation -The **network traffic sensitive data log** including decrypted HTTPS traffic contains the sensitive data you entered in the app. +The output should contain a network traffic sensitive data log that includes the decrypted HTTPS traffic. ## Evaluation -The test case fails if you can find the sensitive data you entered in the app within the **network traffic sensitive data log** that is not stated in the App Store Privacy declarations. +The test case fails if you can find the sensitive data you entered in the app that is not stated in the App Store Privacy declarations. + +Note that this test does not provide any code locations where the sensitive data is being sent over the network. In order to identify the code locations, you can use static analysis tools like [semgrep](https://semgrep.dev/) or dynamic analysis tools like [Frida](https://frida.re/). diff --git a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/risk.md b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/risk.md index bfec8556ce..c6d4209ee6 100644 --- a/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/risk.md +++ b/risks/MASVS-PRIVACY/1-data-minimization/sensitive-data-in-network-traffic/risk.md @@ -4,9 +4,9 @@ alias: sensitive-data-in-network-traffic platform: ["android", "ios"] profiles: ["P"] mappings: -- masvs-v1: [MSTG-NETWORK-1] -- masvs-v2: [MASVS-PRIVACY-1] -- cwe: [359] + masvs-v1: [MSTG-NETWORK-1] + masvs-v2: [MASVS-PRIVACY-1] + cwe: [359] --- ## Overview diff --git a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/test.md b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/test.md index e85c82452a..bdbd52c181 100644 --- a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/test.md +++ b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/android-data-in-logs-frida/test.md @@ -12,21 +12,13 @@ On Android platforms, logging APIs like `Log`, `Logger`, `System.out.print`, `Sy ## Steps 1. Install and run the app. - 2. Navigate to the screen of the mobile app you want to analyse the log output from. - -3. Execute a [method trace](https://mas.owasp.org/MASTG/techniques/android/MASTG-TECH-00xx/) by attaching to the running app, targeting logging APIs and save the output. +3. Execute a [method trace](../../../../../techniques/android/MASTG-TECH-0033.md) by attaching to the running app, targeting logging APIs and save the output. ## Observation -The **method trace output** contains a list of locations where logging APIs are used in the app for the current execution. +The output should contain a list of locations where logging APIs are used in the app for the current execution. ## Evaluation The test case fails if you can find sensitive data being logged using those APIs. - -For example, the following output leaks a key via `Log`: - -```shell -Log.println_native(0, 4, "tag", "key: 12345678") -``` diff --git a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/risk.md b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/risk.md index 05377c4090..cc5414676e 100644 --- a/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/risk.md +++ b/risks/MASVS-STORAGE/2-prevent-data-leakage/data-in-logs/risk.md @@ -4,17 +4,17 @@ alias: data-in-logs platform: ["android", "ios"] profiles: ["L1", "L2", "P"] mappings: - - masvs-v1: [MSTG-STORAGE-7] - - masvs-v2: [MASVS-STORAGE-2, MASVS-PRIVACY-1] - - cwe: [200, 359, 497, 532] - - android: https://developer.android.com/topic/security/risks/log-info-disclosure + masvs-v1: [MSTG-STORAGE-7] + masvs-v2: [MASVS-STORAGE-2, MASVS-PRIVACY-1] + cwe: [200, 359, 497, 532] + android: https://developer.android.com/privacy-and-security/risks/log-info-disclosure refs: - https://stackoverflow.com/questions/45270547/is-read-logs-a-normal-or-dangerous-android-permission --- ## Overview -Mobile apps may write [sensitive data](MASTG-THEORY-0023.md "Sensitive Data") to [logs](MASTG-THEORY-0033.md "Logs"). This may include sensitive user data, such as passwords, credit card numbers, or other personally identifiable information (PII), as well as sensitive system data, such as cryptographic keys, session tokens, or other sensitive information. +Mobile apps may write [sensitive data](../../../../Document/0x04b-Mobile-App-Security-Testing.md#identifying-sensitive-data "Sensitive Data") to logs. This may include sensitive user data, such as passwords, credit card numbers, or other personally identifiable information (PII), as well as sensitive system data, such as cryptographic keys, session tokens, or other sensitive information. Logging all possible information is very useful at development time, especially for debugging the app. However, in production it might not always be necessary and should be prevented whenever possible to avoid any accidentally exposure to potential attackers. diff --git a/src/scripts/populate_dynamic_pages.py b/src/scripts/populate_dynamic_pages.py index ce1c55e110..f65b854722 100644 --- a/src/scripts/populate_dynamic_pages.py +++ b/src/scripts/populate_dynamic_pages.py @@ -48,6 +48,8 @@ def list_of_dicts_to_md_table(data, column_titles=None, column_align=None): def append_to_file(new_content, file_path): file = Path(file_path) + if not file.exists(): + file.touch() content = file.read_text() + new_content file.write_text(content) @@ -73,6 +75,25 @@ def get_mastg_components_dict(name): components.append(frontmatter) return components +def get_all_weaknessess(): + # weaknessess are located in the MASWE folder and all such files are called risk.md. + # We need to retrieve all of them and get their frontmatter, then return them as a list of dictionaries. + weaknesses = [] + for file in glob.glob("docs/MASWE/**/risk.md", recursive=True): + with open(file, 'r') as f: + content = f.read() + + frontmatter = next(yaml.load_all(content, Loader=yaml.FullLoader)) + # set path in frontmatter as the path from MASWE folder as is + frontmatter['path'] = f"/MASWE/{os.path.splitext(os.path.relpath(file, 'docs/MASWE'))[0]}" + # id is a link containing the alias and this path + frontmatter['id'] = f"[{frontmatter['alias']}]({frontmatter['path']})" + frontmatter['masvs_v2_id'] = frontmatter['mappings']['masvs-v2'][0] + frontmatter['masvs_category'] = frontmatter['masvs_v2_id'][:frontmatter['masvs_v2_id'].rfind('-')] + + weaknesses.append(frontmatter) + return weaknesses + def reorder_dict_keys(original_dict, key_order): return {key: original_dict.get(key, "N/A") for key in key_order} @@ -136,6 +157,18 @@ def reorder_dict_keys(original_dict, key_order): apps_of_type = [reorder_dict_keys(app, column_titles.keys()) for app in apps if app['platform'] == app_type] append_to_file(list_of_dicts_to_md_table(apps_of_type, column_titles) + "\n\n
\n\n", "docs/MASTG/apps/index.md") +# weaknesses/overview.md + +column_titles = {'id': 'Alias', 'title': 'Title', 'platform': "Platform", 'masvs_v2_id': "MASVS v2 ID", 'profiles': 'Profiles'} + +weaknesses = get_all_weaknessess() +masvs_categories = ["MASVS-STORAGE", "MASVS-CRYPTO", "MASVS-AUTH", "MASVS-NETWORK", "MASVS-PLATFORM", "MASVS-CODE","MASVS-RESILIENCE", "MASVS-PRIVACY"] + +for masvs_category in masvs_categories: + append_to_file(f"## {masvs_category}\n\n
\n\n", "docs/MASWE/overview.md") + weaknesses_of_type = [reorder_dict_keys(weakness, column_titles.keys()) for weakness in weaknesses if weakness['masvs_category'] == masvs_category] + append_to_file(list_of_dicts_to_md_table(weaknesses_of_type, column_titles) + "\n\n
\n\n", "docs/MASWE/overview.md") + # talks.md data = yaml.safe_load(open("docs/assets/data/talks.yaml"))