<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: MichaelSPeralta</title>
    <description>The latest articles on DEV Community by MichaelSPeralta (@michaelsperalta).</description>
    <link>https://dev.to/michaelsperalta</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F906740%2F7228986a-2bab-476a-947a-6048e1f43aea.png</url>
      <title>DEV Community: MichaelSPeralta</title>
      <link>https://dev.to/michaelsperalta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/michaelsperalta"/>
    <language>en</language>
    <item>
      <title>Crear instaladores ejecutables para windows con scripts en python.</title>
      <dc:creator>MichaelSPeralta</dc:creator>
      <pubDate>Fri, 25 Oct 2024 03:36:41 +0000</pubDate>
      <link>https://dev.to/michaelsperalta/crear-instaladores-ejecutables-para-windows-con-scripts-en-python-39b9</link>
      <guid>https://dev.to/michaelsperalta/crear-instaladores-ejecutables-para-windows-con-scripts-en-python-39b9</guid>
      <description>&lt;p&gt;Otra entrada técnica. &lt;/p&gt;

&lt;p&gt;Contexto rapido, tengo un back y un front (bien bien beta) en python (flask). Los levanto el local en el browser.&lt;/p&gt;

&lt;p&gt;El back levanta en el puerto &lt;code&gt;flask run --port=5001&lt;/code&gt;&lt;br&gt;
El front levanta en el puerto &lt;code&gt;flask run --port=5000&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;La app se ejecuta en el browser.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://localhost:5000/" rel="noopener noreferrer"&gt;http://localhost:5000/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Basico, hasta acá nada nuevo.&lt;/p&gt;

&lt;p&gt;Tengo que instalar esta app en otra maquina. Pensamiento 1 instalar python y todas las librerias y dependecias y... no. &lt;/p&gt;

&lt;p&gt;Acá entra Copilot de nuevo al rescate. Le promptee consejos para instalar estos scripts python como ejecutables para windows. &lt;/p&gt;

&lt;p&gt;Me recomendo algunas cosas interesantes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Antes que nada, tener el entorno virtual levantado, las dependencias instaladas, asegurarse de que todo funciona correctamente en local y... &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Primero usar pyinstaller para generar archivos .exe de mis apps.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pip install pyinstaller&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;En cada directorio ejecuto:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/mi-proyecto/backend&lt;/code&gt;&lt;br&gt;
&lt;code&gt;/mi-proyecto/frontend&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pyinstaller --onefile --name backend app.py&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Acá me fue necesario especificar pasar los templates como parametro, porque daba un error de jynga2&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;pyinstaller --onefile --name frontend --add-data&lt;br&gt;
"templates;templates" app.py&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ejemplo:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nqrzly07lbuzhwi7zcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nqrzly07lbuzhwi7zcw.png" alt="Image description" width="646" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paso siguente, instalar Inno Setup para generar instaladores.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jrsoftware.org/isdl.php" rel="noopener noreferrer"&gt;web - Inno Setup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bueno tuve que promtear algo tambien para tener una base, porque no tenia idea como escribir el script ni la sintaxis de Inno setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Setup]
AppName=My Awesome APP 
AppVersion=1.0
DefaultDirName={pf}\MyAwesomeAPP 
DefaultGroupName=My Awesome APP
OutputBaseFilename=MyAwesomeAPP
Compression=lzma
SolidCompression=yes

[Files]
; Incluir todos los archivos del proyecto
Source: "C:\Users\url-a-tu-proyecto\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs
; Incluir los ejecutables generados por pyinstaller
Source: "C:\Users\url-a-tu-proyecto\frontend\dist\frontend.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Users\url-a-tu-proyecto\backend\dist\backend.exe"; DestDir: "{app}"; Flags: ignoreversion

[Icons]
Name: "{group}\My Awesome APP"; Filename: "{app}\frontend.exe"
Name: "{group}\My Awesome APP"; Filename: "{app}\backend.exe"

[Run]
; Ejecutar el backend
Filename: "{app}\backend.exe"; Flags: nowait
; Ejecutar el frontend
Filename: "{app}\frontend.exe"; Flags: nowait
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta fue mi estructura base. &lt;/p&gt;

&lt;p&gt;Compile, espere unos minutos... y me genero el output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr09jp5yswmdt8bljo7l4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr09jp5yswmdt8bljo7l4.png" alt="Image description" width="683" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y aqui esta el primer instalador :D &lt;/p&gt;

&lt;p&gt;A la primera claramente no anduvo... pero 16 pruebas mas tarde, la app quedo corriendo. Los scripts ejecutandose... &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3wc1rpimq7n3v1yamjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3wc1rpimq7n3v1yamjz.png" alt="Image description" width="405" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y desde mi browser pude acceder a mi app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcao036432hjfr3chftey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcao036432hjfr3chftey.png" alt="Image description" width="509" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lo interesante de esta cuestion, las herramientas! Obviamente. Lo que me gusta, me resulto rapido y facil el uso de inno setup, aprendí a lidir con algunas cuestiones de configuracion de pyinstaller, como las flags para los templates... bien raro el error :P&lt;/p&gt;

&lt;p&gt;Y el uso de nuevas tecnologias y python siempre es agradable... &lt;/p&gt;

&lt;p&gt;La proxima quiza alguna app de escritorio con estos scripts, para optimizar un poco el tamaño final, la arquitectura de archivos y claramente que no esten los terminales ejecutandose en vivo y en directo, con mensajes de entornos de desarrollo y teniendo que entrar a un localhost desde el browser! :panic&lt;/p&gt;

</description>
      <category>python</category>
      <category>innosetup</category>
    </item>
    <item>
      <title>Cómo Realizar y Detectar Ataques de Path Injection</title>
      <dc:creator>MichaelSPeralta</dc:creator>
      <pubDate>Sat, 19 Oct 2024 03:09:19 +0000</pubDate>
      <link>https://dev.to/michaelsperalta/como-realizar-y-detectar-ataques-de-path-injection-3457</link>
      <guid>https://dev.to/michaelsperalta/como-realizar-y-detectar-ataques-de-path-injection-3457</guid>
      <description>&lt;p&gt;Antes que nada, no soy especialista en el tema, estoy aprendiendo y divirtiendome haciendo uso de herramientas de IA.&lt;/p&gt;

&lt;p&gt;Dicho eso... Estuve realizando un desarrollo para un amigo, tiene un PDF con 100 hojas, con registros de transacciones bancarias. Necesita tener estos registros en un excel para poder procesarlo despues.&lt;/p&gt;

&lt;p&gt;Con el uso de Github copilot, realice un script para la extraccion de datos usando python y algunas librerias... Tres doritos despues... Y como desayuno, almuerzo y ceno sistemas, levante un servidor flask, para servir el script atravez de un endpoint en un front con html, css y js puro y duro.&lt;/p&gt;

&lt;p&gt;Durante el proceso de interaccion con Copilot, me levanto una alerta que una parte del código tenia una vulnerabilidad del tipo "path injection". Bastante interesante esta alerta :D&lt;/p&gt;

&lt;p&gt;Y como estoy en busqueda de aprender mas sobre seguridad informatica, acá estoy blogeando para dejar registro de este journey...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Acá empieza a hablar la IA.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Un atacante podría explotar una vulnerabilidad de path injection manipulando la entrada del usuario para acceder a archivos o directorios no autorizados en el sistema de archivos del servidor. Aquí tienes un ejemplo de cómo podría hacerlo:&lt;/p&gt;

&lt;h2&gt;
  
  
  Ejemplo de Path Injection
&lt;/h2&gt;

&lt;p&gt;Supongamos que tienes una ruta en tu aplicación Flask que permite a los usuarios subir archivos y guardarlos en el servidor. Si no validas o sanitizas el nombre del archivo, un atacante podría enviar un nombre de archivo malicioso para intentar acceder a archivos sensibles en el sistema.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Código Vulnerable&lt;/u&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.route('/upload', methods=['POST'])
def upload():
    file = request.files['file']
    filename = file.filename  # Nombre del archivo proporcionado por el usuario
    save_path = os.path.join('uploads', filename)

    # Guardar el archivo sin validar el nombre del archivo
    with open(save_path, 'wb') as f:
        f.write(file.read())

    return 'File uploaded successfully'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;u&gt;Ataque de Path Injection&lt;/u&gt;&lt;br&gt;
Un atacante podría enviar una solicitud con un nombre de archivo malicioso como ../../etc/passwd. Esto podría resultar en la siguiente ruta:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;uploads/../../etc/passwd&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Si el servidor no valida ni &lt;em&gt;sanitiza&lt;/em&gt; el nombre del archivo, el archivo podría ser guardado en una ubicación no deseada, permitiendo al atacante sobrescribir archivos sensibles en el sistema.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Solución: Validar y Sanitizar la Entrada&lt;/u&gt;&lt;br&gt;
Para evitar este tipo de ataques, debes validar y sanitizar el nombre del archivo antes de guardarlo. Aquí tienes una versión segura del código:&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Código Seguro&lt;/u&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
import re
from flask import Flask, render_template, request, send_file
import requests
from datetime import datetime

app = Flask(__name__)

def sanitize_filename(filename):
    # Eliminar caracteres no permitidos del nombre del archivo
    return re.sub(r'[^a-zA-Z0-9_\-\.]', '', filename)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/upload', methods=['POST'])
def upload():
    file = request.files['file']
    response = requests.post('http://127.0.0.1:5001/pdf-to-excel', files={'file': file})

    # Obtener la fecha actual
    current_date = datetime.now().strftime("%Y%m%d")

    # Obtener el nombre original del archivo sin la extensión
    original_filename = os.path.splitext(file.filename)[0]

    # Sanitizar el nombre del archivo
    sanitized_filename = sanitize_filename(original_filename)

    # Crear el nuevo nombre del archivo con la fecha al final
    output_filename = f'{sanitized_filename}_{current_date}.xlsx'

    # Crear la ruta completa del archivo
    save_path = os.path.join('uploads', output_filename)

    # Asegurarse de que la ruta sea absoluta
    save_path = os.path.abspath(save_path)

    # Guardar el archivo Excel resultante localmente con el nuevo nombre
    with open(save_path, 'wb') as f:
        f.write(response.content)

    # Enviar el archivo Excel de vuelta al usuario con el nuevo nombre
    return send_file(save_path, as_attachment=True, download_name=output_filename)

if __name__ == '__main__':
    app.run(port=5000, debug=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;u&gt;Explicación del Código Seguro&lt;/u&gt;&lt;br&gt;
Sanitizar el Nombre del Archivo: La función sanitize_filename elimina caracteres no permitidos del nombre del archivo utilizando una expresión regular.&lt;/p&gt;

&lt;p&gt;Crear la Ruta Completa del Archivo: La función os.path.join se utiliza para crear la ruta completa del archivo, combinando el directorio de destino (uploads) con el nombre del archivo sanitizado (output_filename).&lt;/p&gt;

&lt;p&gt;Asegurarse de que la Ruta sea Absoluta: La función os.path.abspath convierte la ruta en una ruta absoluta para evitar manipulaciones con rutas relativas.&lt;/p&gt;

&lt;p&gt;Guardar el Archivo: Finalmente, el archivo se guarda en la ruta especificada.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Resumen&lt;/u&gt;&lt;br&gt;
Path Injection: Un atacante puede manipular la entrada del usuario para acceder a archivos o directorios no autorizados.&lt;br&gt;
Validación y Sanitización: Siempre valida y sanitiza las entradas del usuario para evitar ataques de path injection.&lt;br&gt;
Rutas Absolutas: Utiliza rutas absolutas para evitar manipulaciones con rutas relativas.&lt;br&gt;
Siguiendo estas prácticas, puedes proteger tu aplicación contra ataques de path injection y mejorar la seguridad general de tu sistema.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Acá le pregunté el how to para llegar a realizar el ataque. Además que me dejé registrados logs para poder depurar estos casos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para asegurar tu aplicación contra ataques de path injection, es útil entender cómo se pueden realizar estos ataques. Aquí te muestro cómo un atacante podría intentar explotar tu aplicación y cómo puedes detectar estas actividades en los logs.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Desde el Navegador
&lt;/h3&gt;

&lt;p&gt;Manipulando Formularios HTML&lt;br&gt;
Un atacante puede manipular un formulario HTML para enviar un nombre de archivo malicioso.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Paso a Paso:&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abre la página web con el formulario de subida de archivos.&lt;/li&gt;
&lt;li&gt;Usa las herramientas de desarrollo del navegador (F12) para inspeccionar el formulario.&lt;/li&gt;
&lt;li&gt;Modifica el valor del campo de archivo para incluir una ruta maliciosa, por ejemplo, ../../etc/passwd.&lt;/li&gt;
&lt;li&gt;Envía el formulario.&lt;/li&gt;
&lt;li&gt;Detección en Logs: Registra el nombre del archivo recibido en los logs.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import logging

# Configurar el logging
logging.basicConfig(filename='app.log', level=logging.INFO)

@app.route('/upload', methods=['POST'])
def upload():
    file = request.files['file']
    logging.info(f"Archivo recibido: {file.filename}")

    # Resto del código...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  2. Usando Herramientas como Postman
&lt;/h3&gt;

&lt;p&gt;Enviando Solicitudes HTTP Manipuladas&lt;br&gt;
Un atacante puede usar Postman para enviar solicitudes HTTP manipuladas directamente al servidor.&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Paso a Paso:&lt;/u&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abre Postman y configura una solicitud POST a &lt;a href="http://127.0.0.1:5000/upload" rel="noopener noreferrer"&gt;http://127.0.0.1:5000/upload&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;En el cuerpo de la solicitud, selecciona form-data y añade un campo file con un archivo cuyo nombre sea ../../etc/passwd.&lt;/li&gt;
&lt;li&gt;Envía la solicitud.&lt;/li&gt;
&lt;li&gt;Detección en Logs: Registra el nombre del archivo recibido en los logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3. Mediante Scripts Automatizados
&lt;/h3&gt;

&lt;p&gt;Usando Scripts en Python&lt;br&gt;
Un atacante puede usar scripts en Python para enviar solicitudes HTTP maliciosas.&lt;/p&gt;

&lt;p&gt;Ejemplo de Script en Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import requests

url = 'http://127.0.0.1:5000/upload'
files = {'file': ('../../etc/passwd', open('local_file.txt', 'rb'))}
response = requests.post(url, files=files)
print(response.text)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detección en Logs: Registra el nombre del archivo recibido en los logs.&lt;/p&gt;

&lt;p&gt;Implementación de Logs para Detección&lt;br&gt;
Aquí tienes una implementación completa que incluye logging para detectar nombres de archivos sospechosos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask, render_template, request, send_file
import requests
from datetime import datetime
import os
import re
import logging

# Configurar el logging
logging.basicConfig(filename='app.log', level=logging.INFO)

app = Flask(__name__)

def sanitize_filename(filename):
    # Eliminar caracteres no permitidos del nombre del archivo
    return re.sub(r'[^a-zA-Z0-9_\-\.]', '', filename)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/upload', methods=['POST'])
def upload():
    file = request.files['file']
    logging.info(f"Archivo recibido: {file.filename}")

    response = requests.post('http://127.0.0.1:5001/pdf-to-excel', files={'file': file})

    # Obtener la fecha actual
    current_date = datetime.now().strftime("%Y%m%d")

    # Obtener el nombre original del archivo sin la extensión
    original_filename = os.path.splitext(file.filename)[0]

    # Sanitizar el nombre del archivo
    sanitized_filename = sanitize_filename(original_filename)

    # Crear el nuevo nombre del archivo con la fecha al final
    output_filename = f'{sanitized_filename}_{current_date}.xlsx'

    # Crear la ruta completa del archivo
    save_path = os.path.join('uploads', output_filename)

    # Asegurarse de que la ruta sea absoluta
    save_path = os.path.abspath(save_path)

    # Guardar el archivo Excel resultante localmente con el nuevo nombre
    with open(save_path, 'wb') as f:
        f.write(response.content)

    logging.info(f"Archivo guardado en: {save_path}")

    # Enviar el archivo Excel de vuelta al usuario con el nuevo nombre
    return send_file(save_path, as_attachment=True, download_name=output_filename)

if __name__ == '__main__':
    app.run(port=5000, debug=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;u&gt;Resumen&lt;/u&gt;&lt;br&gt;
Desde el Navegador: Manipulando formularios HTML o usando herramientas de desarrollo del navegador.&lt;br&gt;
Usando Herramientas como Postman: Enviando solicitudes HTTP manipuladas directamente al servidor.&lt;br&gt;
Mediante Scripts Automatizados: Usando scripts en Python, Bash, o cualquier otro lenguaje para enviar solicitudes HTTP maliciosas.&lt;br&gt;
Detección en Logs: Registra el nombre del archivo recibido y otras actividades sospechosas en los logs para detectar posibles ataques.&lt;br&gt;
Implementando estas medidas, puedes mejorar la seguridad de tu aplicación y detectar actividades sospechosas que podrían indicar un intento de ataque.&lt;/p&gt;

&lt;p&gt;Conclución: Bajo este contexto de aprendizaje y desarrollo haciendo pair programming con la IA, me parece sumamente útil este tipo de alertas en la plataforma para detectar vulnerabilidades. Hoy me levante pensando que iba a deployar a heroku el back y acá me encuentro descubriendo distintas vulnerabilidades :D &lt;/p&gt;

&lt;p&gt;happy coding! &lt;/p&gt;

</description>
      <category>ai</category>
      <category>githubcopilot</category>
      <category>python</category>
      <category>security</category>
    </item>
  </channel>
</rss>
